Hvis du har med NVARCHAR
at gøre / NCHAR
data (som er gemt som UTF-16 Little Endian ), så ville du bruge Unicode
kodning, ikke BigEndianUnicode
. I .NET hedder UTF-16 Unicode
mens andre Unicode-kodninger omtales med deres faktiske navne:UTF7, UTF8 og UTF32. Derfor Unicode
i sig selv er Lille Endian
i modsætning til BigEndianUnicode
. OPDATERING: Se venligst afsnittet i slutningen vedrørende UCS-2 og supplerende tegn.
På databasesiden:
VÆLG HASHBYTES('MD5', N'è') AS [HashBytesNVARCHAR]-- FAC02CD988801F0495D35611223782CF
På .NET-siden:
System.Text.Encoding.ASCII.GetBytes("è")// D1457B72C3FB323A2671125AEF3EAB5DSystem.Text.Encoding.UTF7.GetBytes("è")// F63A0999FE5999DE5369DE7369.TUTFètes ")// 0A35E149DBBB2D10D744BF675C7744B1System.Text.Encoding.UTF32.GetBytes("è")// 86D29922AC56CF022B639187828137F8System.Text.Encoding.BigEndianUnicode.GetBytes("è")// 407256AC97E4C5AEBCA825DEB3D2E89CSystem.Text.Encoding.Unicode.GetBytes("è") // denne matcher HASHBYTES('MD5', N'è')// FAC02CD988801F0495D35611223782CF
Dette spørgsmål vedrører dog VARCHAR
/ CHAR
data, som er ASCII, og så tingene er lidt mere komplicerede.
På databasesiden:
VÆLG HASHBYTES('MD5', 'è') SOM [HashBytesVARCHAR]-- 785D512BE4316D578E6650613B45E934
Vi ser allerede .NET-siden ovenfor. Fra disse hash-værdier burde der være to spørgsmål:
- Hvorfor ikke nogle af dem matcher
HASHBYTES
værdi? - Hvorfor viser "sqlteam.com"-artiklen, der er linket til i @Eric J.s svar, at tre af dem (
ASCII
,UTF7
ogUTF8
) matcher alleHASHBYTES
værdi?
Der er ét svar, der dækker begge spørgsmål:Kodesider. Testen udført i "sqlteam"-artiklen brugte "sikre" ASCII-tegn, der er i intervallet 0 - 127 (med hensyn til int / decimalværdien), som ikke varierer mellem kodesider. Men intervallet 128 - 255 -- hvor vi finder tegnet "è" -- er Udvidet sæt, der varierer efter kodeside (hvilket giver mening, da dette er grunden til at have kodesider).
Prøv nu:
SELECT HASHBYTES('MD5', 'è' COLLATE SQL_Latin1_General_CP1255_CI_AS) AS [HashBytes]-- D1457B72C3FB323A2671125AEF3EAB5D
Det matcher ASCII
hashed værdi (og igen, fordi "sqlteam" artiklen / testen brugte værdier i intervallet 0 - 127, så de ingen ændringer ved brug af COLLATE
). Godt, nu har vi endelig fundet en måde at matche VARCHAR
/ CHAR
data. Alt godt?
Nå, ikke rigtig. Lad os tage et kig på, hvad vi rent faktisk hash:
VÆLG 'è' AS [TheChar], ASCII('è') AS [TheASCIIvalue], 'è' COLLATE SQL_Latin1_General_CP1255_CI_AS AS [CharCP1255], ASCII('è' COLLATE SQL_Latin1_General_CP1255) [CP12CII5) [CP12CII5]. /kode>
Returnerer:
TheChar TheASCIIvalue CharCP1255 TheASCIIvalueCP1255è 232 ? 63
En ?
? Bare for at bekræfte, kør:
VÆLG CHAR(63) AS [WhatIs63?];-- ?
Ah, så Code Page 1255 har ikke è
tegn, så det bliver oversat som alles favorit ?
. Men hvorfor matchede det så MD5-hash-værdien i .NET, når du brugte ASCII-kodning? Kunne det være, at vi faktisk ikke matchede den hashed værdi af è
, men i stedet matchede den hash-kodede værdi af ?
:
VÆLG HASHBYTES('MD5', '?') SOM [HashBytesVARCHAR]-- 0xD1457B72C3FB323A2671125AEF3EAB5D
Jep. Det ægte ASCII-tegnsæt er kun de første 128 tegn (værdier 0 - 127). Og som vi lige så, è
er 232. Så ved at bruge ASCII
kodning i .NET er ikke så nyttig. Brugte heller ikke COLLATE
på T-SQL-siden.
Er det muligt at få en bedre kodning på .NET-siden? Ja, ved at bruge Encoding.GetEncoding(Int32), som gør det muligt at angive kodesiden. Kodesiden, der skal bruges, kan findes ved hjælp af følgende forespørgsel (brug sys.columns
når du arbejder med en kolonne i stedet for en bogstavelig eller variabel):
VÆLG sd.[collation_name], COLLATIONPROPERTY(sd.[collation_name], 'CodePage') SOM [CodePage]FRA sys.databases sdWHERE sd.[navn] =DB_NAME(); -- Erstat funktionen med N'{db_name}', hvis den ikke kører i DB
Forespørgslen ovenfor returnerer (for mig):
Latin1_General_100_CI_AS_SC 1252
Så lad os prøve Kode Side 1252:
System.Text.Encoding.GetEncoding(1252).GetBytes("è") // Matcher HASHBYTES('MD5', 'è')// 785D512BE4316D578E6650613B45E934
Hov hov! Vi har et match til VARCHAR
data, der bruger vores standard SQL Server-sortering :). Selvfølgelig, hvis dataene kommer fra en database eller et felt, der er sat til en anden sortering, så GetEncoding(1252)
måske ikke virker, og du bliver nødt til at finde den faktiske matchende kodeside ved hjælp af forespørgslen vist ovenfor (en kodeside bruges på tværs af mange sorteringer, så en anden sortering er ikke nødvendigvis antyde en anden kodeside).
For at se, hvad de mulige kodesideværdier er, og hvilken kultur/lokalitet de vedrører, se venligst listen over kodesider her (listen er i afsnittet "Bemærkninger").
Yderligere oplysninger relateret til, hvad der faktisk er gemt i NVARCHAR
/ NCHAR
felter:
Ethvert UTF-16-tegn (2 eller 4 bytes) kan lagres, selvom standardadfærden for de indbyggede funktioner forudsætter, at alle tegn er UCS-2 (2 bytes hver), som er en delmængde af UTF-16. Fra og med SQL Server 2012 er det muligt at få adgang til et sæt Windows-kollationer, der understøtter de 4 byte-tegn kendt som Supplerende tegn. Brug af en af disse Windows-sammenstillinger, der ender på _SC
, enten angivet for en kolonne eller direkte i en forespørgsel, vil tillade de indbyggede funktioner at håndtere de 4 byte tegn korrekt.
-- Databasens sortering er indstillet til:SQL_Latin1_General_CP1_CI_ASSELECT N'𨝫' AS [Supplementary Character], LEN(N'𨝫') AS [LEN], DATALENGTH(N'𨝫') AS [DATALENGTH], UNICODE (N'𨝫') AS [UNICODE], LEFT(N'𨝫', 1) AS [LEFT], HASHBYTES('MD5', N'𨝫') AS [HASHBYTES];SELECT N'𨝫' AS [Supplerende tegn] , LEN(N'𨝫' COLLATE Latin1_General_100_CI_AS_SC) AS [LEN], DATALENGTH(N'🨝' COLLATE Latin1_General_100_CI_AS_SC) AS [DATALENGTH], UNICODE(N'𨝫' COLLATE Latin_1_SCODE)'N COLLATE Latin1_General_100_CI_AS_SC, 1) AS [LEFT], HASHBYTES('MD5', N'𨝫' SAMLER Latin1_General_100_CI_AS_SC) AS [HASHBYTES];
Returnerer:
SupplementaryChar LEN DATALENGTH UNICODE LEFT HASHBYTES𨝫 2 4 55393 � 0x7A04F43DA81E3150F539C6B99F4B8FA9💫 1 4 165739 37B504039F69A 37B5040 365739 365739 365739 365739 365739 365739
Som du kan se, hverken DATALENGTH
heller ikke HASHBYTES
er ramt. For mere information, se venligst MSDN-siden for Collation og Unicode Support (specifikt afsnittet "Supplerende tegn").