sql >> Databasteknik >  >> RDS >> Sqlserver

Vad är poängen med SAMLINGAR för nvarchar (Unicode)-kolumner?

Att lagra och representera karaktärer är en sak, och att veta hur man sorterar och jämför dem är en annan.

Unicode-data, lagrad i XML och N -prefixtyper i SQL Server, kan representera alla tecken på alla språk (för det mesta, och det är dess mål) med en enda teckenuppsättning. Så för NCHAR / NVARCHAR data (jag utelämnar NTEXT eftersom det inte ska användas längre, och XML eftersom det inte påverkas av sorteringar) ändrar inte sorteringarna vilka tecken som kan lagras. För CHAR och VARCHAR data, sorteringarna gör påverka vad som kan lagras när varje sortering pekar på en viss kodsida, som bestämmer vad som kan lagras i värdena 128 - 255.

Nu, även om det finns en standardsorteringsordning för alla tecken, kan det omöjligt fungera över alla språk och kulturer. Det finns många språk som delar vissa/många/alla karaktärer, men har olika regler för hur man sorterar dem. Till exempel kommer bokstaven "C" före bokstaven "D" i de flesta alfabet som använder dessa bokstäver. På amerikansk engelska skulle en kombination av "C" och "H" (dvs. "CH" som två separata bokstäver) naturligtvis komma före varje sträng som börjar med ett "D". Men på några språk är kombinationen av två bokstäver av "CH" speciell och sorterar efter "D":

IF (   N'CH' COLLATE Czech_CI_AI > N'D' COLLATE Czech_CI_AI
   AND N'C'  COLLATE Czech_CI_AI < N'D' COLLATE Czech_CI_AI
   AND N'CI' COLLATE Czech_CI_AI < N'D' COLLATE Czech_CI_AI
   ) PRINT 'Czech_CI_AI';

IF (   N'CH' COLLATE Czech_100_CI_AI > N'D' COLLATE Czech_100_CI_AI
   AND N'C'  COLLATE Czech_100_CI_AI < N'D' COLLATE Czech_100_CI_AI
   AND N'CI' COLLATE Czech_100_CI_AI < N'D' COLLATE Czech_100_CI_AI
   ) PRINT 'Czech_100_CI_AI';

IF (   N'CH' COLLATE Slovak_CI_AI > N'D' COLLATE Slovak_CI_AI
   AND N'C'  COLLATE Slovak_CI_AI < N'D' COLLATE Slovak_CI_AI
   AND N'CI' COLLATE Slovak_CI_AI < N'D' COLLATE Slovak_CI_AI
   ) PRINT 'Slovak_CI_AI';

IF (   N'CH' COLLATE Slovak_CS_AS > N'D' COLLATE Slovak_CS_AS
   AND N'C'  COLLATE Slovak_CS_AS < N'D' COLLATE Slovak_CS_AS
   AND N'CI' COLLATE Slovak_CS_AS < N'D' COLLATE Slovak_CS_AS
   ) PRINT 'Slovak_CS_AS';

IF (   N'CH' COLLATE Latin1_General_100_CI_AS > N'D' COLLATE Latin1_General_100_CI_AS
   AND N'C'  COLLATE Latin1_General_100_CI_AS < N'D' COLLATE Latin1_General_100_CI_AS
   AND N'CI' COLLATE Latin1_General_100_CI_AS < N'D' COLLATE Latin1_General_100_CI_AS
   ) PRINT 'Latin1_General_100_CI_AS'
ELSE PRINT 'Nope!';

Returnerar:

Czech_CI_AI
Czech_100_CI_AI
Slovak_CI_AI
Slovak_CS_AS
Nope!

För att se exempel på sorteringsregler över olika kulturer, se:Sorteringsdiagram .

På vissa språk är vissa bokstäver eller kombinationer av bokstäver lika med andra bokstäver på sätt som de inte gör på de flesta andra språk. Till exempel, bara på danska är ett "å" lika med "aa". Men "å" är inte lika med bara ett enda "a":

IF (N'aa' COLLATE Danish_Greenlandic_100_CI_AI =  N'å' COLLATE Danish_Greenlandic_100_CI_AI
AND N'a'  COLLATE Danish_Greenlandic_100_CI_AI <> N'å' COLLATE Danish_Greenlandic_100_CI_AI
   ) PRINT 'Danish_Greenlandic_100_CI_AI';

IF (   N'aa' COLLATE Danish_Norwegian_CI_AI =  N'å' COLLATE Danish_Norwegian_CI_AI
   AND N'a'  COLLATE Danish_Norwegian_CI_AI <> N'å' COLLATE Danish_Norwegian_CI_AI
   ) PRINT 'Danish_Norwegian_CI_AI';

IF (   N'aa' COLLATE Latin1_General_100_CI_AI =  N'å' COLLATE Latin1_General_100_CI_AI
   AND N'a'  COLLATE Latin1_General_100_CI_AI <> N'å' COLLATE Latin1_General_100_CI_AI
   ) PRINT 'Latin1_General_100_CI_AI'
ELSE PRINT 'Nope!';

Returnerar:

Danish_Greenlandic_100_CI_AI
Danish_Norwegian_CI_AI
Nope!

Allt detta är mycket komplicerat, och jag har inte ens nämnt hantering för höger-till-vänster-språk (hebreiska och arabiska), kinesiska, japanska, kombination av tecken, etc.

Om du vill ha lite djupare insikt i reglerna, kolla in Unicode Collation Algorithm (UCA) . Exemplen ovan är baserade på exempel i den dokumentationen, även om jag inte tror att alla regler i UCA har implementerats, speciellt sedan Windows-kollationerna (kollationer inte börjar med SQL_ ) är baserade på Unicode 5.0 eller 6.0, beroende på vilket operativsystem du använder och vilken version av .NET Framework som är installerad (se SortVersion för detaljer).

Så det är vad Collations gör. Om du vill se alla sorteringar som är tillgängliga, kör bara följande:

SELECT [name] FROM sys.fn_helpcollations() ORDER BY [name];


  1. Hämtar UTC DATETIME-fältet från MySQL i Java när serverns tidszon inte är UTC

  2. Skapa en kommaseparerad lista med värden i en Oracle SQL-sats

  3. Varför matchar _ (understreck) - (bindestreck)?

  4. Oracle alter table otillräckliga privilegier