Ordinamento sensibile all'accento


19

Perché queste due SELECTaffermazioni producono un diverso ordinamento?

USE tempdb;
CREATE TABLE dbo.OddSort 
(
    id INT IDENTITY(1,1) PRIMARY KEY
    , col1 NVARCHAR(2)
    , col2 NVARCHAR(2)
);
GO
INSERT dbo.OddSort (col1, col2) 
VALUES (N'e', N'eA')
    , (N'é', N'éB')
    , (N'ë', N'ëC')
    , (N'è', N'èD')
    , (N'ê', N'êE')
    , (N'ē', N'ēF');
GO

SELECT * 
FROM dbo.OddSort 
ORDER BY col1 COLLATE Latin1_General_100_CS_AS;
╔════╦══════╦══════╗
║ id ║ col1 ║ col2 ║
╠════╬══════╬══════╣
║ 1 ║ e ║ eA ║
║ 2 ║ é ║ éB ║
║ 4 ║ è ║ èD ║ - dovrebbe essere id 3?
║ 5 ║ ê ║ êE ║
║ 3 ║ ë ║ ëC ║
║ 6 ║ ē ║ ēF ║
╚════╩══════╩══════╝
SELECT * 
FROM dbo.OddSort 
ORDER BY col2 COLLATE Latin1_General_100_CS_AS;
╔════╦══════╦══════╗
║ id ║ col1 ║ col2 ║
╠════╬══════╬══════╣
║ 1 ║ e ║ eA ║
║ 2 ║ é ║ éB ║
║ 3 ║ ë ║ ëC ║
║ 4 ║ è ║ èD ║
║ 5 ║ ê ║ êE ║
║ 6 ║ ē ║ ēF ║
╚════╩══════╩══════╝

Risposte:


13

Questa domanda non è così correlata ai database ma piuttosto alla gestione e alle regole Unicode.

Basato su https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql Latin1_General_100_CS_AS significa: "Le regole di confronto utilizzano le regole di ordinamento del dizionario latino Latin1 e le mappe alla tabella codici 1252 "con CS = case sensitive aggiunto e AS = accent sensitive.

La mappatura tra la code page di Windows 1252 e Unicode ( http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT ) mostrano gli stessi valori per tutti i personaggi con cui abbiamo a che fare (tranne e con macron che non esiste nella mappatura Microsoft, quindi non ho idea di cosa faccia in questo caso), quindi per ora possiamo concentrarci sugli strumenti e sulla terminologia Unicode.

Per prima cosa, facci sapere esattamente con cosa abbiamo a che fare, per tutte le tue corde:

0065  LATIN SMALL LETTER E
0041  LATIN CAPITAL LETTER A
00E9  LATIN SMALL LETTER E WITH ACUTE
0042  LATIN CAPITAL LETTER B
00EB  LATIN SMALL LETTER E WITH DIAERESIS
0043  LATIN CAPITAL LETTER C
00E8  LATIN SMALL LETTER E WITH GRAVE
0044  LATIN CAPITAL LETTER D
00EA  LATIN SMALL LETTER E WITH CIRCUMFLEX
0045  LATIN CAPITAL LETTER E
0113  LATIN SMALL LETTER E WITH MACRON
0046  LATIN CAPITAL LETTER F

L'algoritmo di confronto Unicode è descritto qui: https://www.unicode.org/reports/tr10/

Dai un'occhiata alla sezione 1.3 "Sensibilità contestuale" che spiega che l'ordinamento non può dipendere da un solo carattere dopo l'altro poiché alcune regole sono sensibili al contesto.

Nota anche questi punti in 1.8:

La collazione non è una proprietà delle stringhe. L'ordine di confronto non viene conservato durante le operazioni di concatenazione o sottostringa, in generale.

Per impostazione predefinita, l'algoritmo utilizza tre livelli completamente personalizzabili. Per la scrittura latina, questi livelli corrispondono approssimativamente a:

alphabetic ordering
diacritic ordering
case ordering.

Ma l'algoritmo di per sé è un po 'denso. L'essenza è: brevemente, l'algoritmo di confronto Unicode accetta una stringa Unicode di input e una tabella degli elementi di confronto, che contiene i dati di mapping per i caratteri. Produce una chiave di ordinamento, che è un array di numeri interi a 16 bit senza segno. Due o più chiavi di ordinamento così prodotte possono quindi essere confrontate binariamente per fornire il corretto confronto tra le stringhe per le quali sono state generate.

È possibile visualizzare le regole di ordinamento latino specifiche qui: http://developer.mimer.com/collations/charts/latin.htm o più direttamente e specificamente per MS SQL: http://collation-charts.org/mssql/mssql. 0409.1252.Latin1_General_CS_AS.html

Per il epersonaggio che mostra:

e E é É è È ê Ê ë Ë

Questo spiega i tuoi risultati al momento dell'ordine, col1tranne per il fatto che ē non esiste nella tabella codici 1252, quindi non ho assolutamente idea di cosa ci faccia.

O se eseguiamo manualmente l'algoritmo Unicode, utilizzando il valore delle chiavi di DUCET su http://www.unicode.org/Public/UCA/latest/allkeys.txt :

passaggio 1: modulo di normalizzazione D, quindi ogni caso diventa:

e => U+0065
é => U+0065 U+0301
ë => U+0065 U+0308
è => U+0065 U+0300
ê => U+0065 U+0302
ē => U+0065 U+0304

passaggio 2, produrre array di confronto (ricerca nel file allkeys.txt)

e => [.1D10.0020.0002]
é => [.1D10.0020.0002] [.0000.0024.0002]
ë => [.1D10.0020.0002] [.0000.002B.0002]
è => [.1D10.0020.0002] [.0000.0025.0002]
ê => [.1D10.0020.0002] [.0000.0027.0002]
ē => [.1D10.0020.0002] [.0000.0032.0002]

passaggio 3, chiavi di ordinamento dei moduli (per ogni livello, prendere ciascun valore all'interno di ciascun array di confronto, quindi inserire 0000 come delimitatore e ricominciare dal livello successivo)

e => 1D10 0000 0020 0000 0002
é => 1D10 0000 0020 0024 0000 0002 0002
ë => 1D10 0000 0020 002B 0000 0002 0002
è => 1D10 0000 0020 0025 0000 0002 0002
ê => 1D10 0000 0020 0027 0000 0002 0002
ē => 1D10 0000 0020 0032 0000 0002 0002

passaggio 4, confronta le chiavi di ordinamento (semplice confronto binario di ogni valore uno per uno): il quarto valore è sufficiente per ordinarli tutti, quindi l'ordine finale diventa:

e
é
è
ê
ë
ē

Allo stesso modo per l'ordinazione su col2:

passaggio 1: NFD

eA => U+0065 U+0041
éB => U+0065 U+0301 U+0042
ëC => U+0065 U+0308 U+0043
èD => U+0065 U+0300 U+0044
êE => U+0065 U+0302 U+0045
ēF => U+0065 U+0304 U+0046

passaggio 2: array di confronto

eA => [.1D10.0020.0002] [.1CAD.0020.0008]
éB => [.1D10.0020.0002] [.0000.0024.0002] [.1CC6.0020.0008]
ëC => [.1D10.0020.0002] [.0000.002B.0002] [.1CE0.0020.0008]
èD => [.1D10.0020.0002] [.0000.0025.0002] [.1CF5.0020.0008]
êE => [.1D10.0020.0002] [.0000.0027.0002] [.1D10.0020.0008]
ēF => [.1D10.0020.0002] [.0000.0032.0002] [.1D4B.0020.0008]

passaggio 3: chiavi di ordinamento dei moduli

eA => 1D10 1CAD 0000 0020 0020 0000 0002 0008
éB => 1D10 1CC6 0000 0020 0024 0020 0000 0002 0002 0008
ëC => 1D10 1CE0 0000 0020 002B 0020 0000 0002 0002 0008
èD => 1D10 1CF5 0000 0020 0025 0020 0000 0002 0002 0008
êE => 1D10 1D10 0000 0020 0027 0020 0000 0002 0002 0008
ēF => 1D10 1D4B 0000 0020 0032 0020 0000 0002 0002 0008

passaggio 4: confronta le chiavi di ordinamento: il secondo valore è sufficiente per ordinarle tutte, ed è infatti già in ordine crescente, quindi l'ordine finale è effettivamente:

eA
éB
ëC
èD
êE
ēF

Aggiornamento : aggiunta del terzo caso Solomon Rutzky, che è più complicato a causa dello spazio che consente nuove regole (ho scelto il "caso non ignorabile"):

passaggio 1, NFD:

è 1 => U+0065 U+0300 U+0020 U+0031
ê 5 => U+0065 U+0302 U+0020 U+0035
e 2 => U+0065 U+0020 U+0032
é 4 => U+0065 U+0301 U+0020 U+0034
ē 3 => U+0065 U+0304 U+0020 U+0033
ë 6 => U+0065 U+0308 U+0020 U+0036

passaggio 2, produrre array di confronto:

è 1 => [.1D10.0020.0002] [.0000.0025.0002] [*0209.0020.0002] [.1CA4.0020.0002]
ê 5 => [.1D10.0020.0002] [.0000.0027.0002] [*0209.0020.0002] [.1CA8.0020.0002]
e 2 => [.1D10.0020.0002] [*0209.0020.0002] [.1CA5.0020.0002]
é 4 => [.1D10.0020.0002] [.0000.0024.0002] [*0209.0020.0002] [.1CA7.0020.0002]
ē 3 => [.1D10.0020.0002] [.0000.0032.0002] [*0209.0020.0002] [.1CA6.0020.0002]
ë 6 => [.1D10.0020.0002] [.0000.002B.0002] [*0209.0020.0002] [.1CA9.0020.0002]

passaggio 3, chiavi di ordinamento dei moduli:

è 1 => 1D10 0209 1CA4 0000 0020 0025 0020 0020 0000 0002 0002 0002 0002
ê 5 => 1D10 0209 1CA8 0000 0020 0027 0020 0020 0000 0002 0002 0002 0002
e 2 => 1D10 0209 1CA5 0000 0020 0020 0020 0000 0002 0002 0002
é 4 => 1D10 0209 1CA7 0000 0020 0024 0020 0020 0000 0002 0002 0002 0002
ē 3 => 1D10 0209 1CA6 0000 0020 0032 0020 0020 0000 0002 0002 0002 0002
ë 6 => 1D10 0209 1CA9 0000 0020 002B 0020 0020 0000 0002 0002 0002 0002

passaggio 4, confronta i tasti di ordinamento:

Fondamentalmente il terzo valore determina l'ordine, ed è in realtà basato solo sull'ultima cifra, quindi l'ordine dovrebbe essere:

è 1
e 2
ē 3
é 4
ê 5
ë 6

Secondo aggiornamento basato sul commento di Solomon Rutzky sulle versioni Unicode.

Ho usato i allkeys.txtdati sull'ultima versione Unicode in questo momento, cioè la versione 10.0

Se invece dovessimo prendere in considerazione Unicode 5.1 , questo sarebbe: http://www.unicode.org/Public/UCA/5.1.0/allkeys.txt

Ho appena controllato, per tutti i personaggi sopra, gli array di confronto sono i seguenti invece:

e => [.119D.0020.0002.0065]
é => [.119D.0020.0002.0065] [.0000.0032.0002.0301]
ë => [.119D.0020.0002.0065] [.0000.0047.0002.0308]
è => [.119D.0020.0002.0065] [.0000.0035.0002.0300]
ê => [.119D.0020.0002.0065] [.0000.003C.0002.0302]
ē => [.119D.0020.0002.0065] [.0000.005B.0002.0304]

e:

eA => [.119D.0020.0002.0065] [.1141.0020.0008.0041]
éB => [.119D.0020.0002.0065] [.0000.0032.0002.0301] [.1157.0020.0008.0042]
ëC => [.119D.0020.0002.0065] [.0000.0047.0002.0308] [.116F.0020.0008.0043]
èD => [.119D.0020.0002.0065] [.0000.0035.0002.0300] [.1182.0020.0008.0044]
êE => [.119D.0020.0002.0065] [.0000.003C.0002.0302] [.119D.0020.0008.0045]
ēF => [.119D.0020.0002.0065] [.0000.005B.0002.0304] [.11D5.0020.0008.0046]

e:

è 1 => [.119D.0020.0002.0065] [.0000.0035.0002.0300] [*0209.0020.0002.0020] [.1138.0020.0002.0031]
ê 5 => [.119D.0020.0002.0065] [.0000.003C.0002.0302] [*0209.0020.0002.0020] [.113C.0020.0002.0035]
e 2 => [.119D.0020.0002.0065] [*0209.0020.0002.0020] [.1139.0020.0002.0032]
é 4 => [.119D.0020.0002.0065] [.0000.0032.0002.0301] [*0209.0020.0002.0020] [.113B.0020.0002.0034]
ē 3 => [.119D.0020.0002.0065] [.0000.005B.0002.0304] [*0209.0020.0002.0020] [.113A.0020.0002.0033]
ë 6 => [.119D.0020.0002.0065] [.0000.0047.0002.0308] [*0209.0020.0002.0020] [.113D.0020.0002.0036]

che poi calcola alle seguenti chiavi di ordinamento:

e => 119D 0000 0020 0000 0002 0000 0065
é => 119D 0000 0020 0032 0000 0002 0002 0000 0065 0301
ë => 119D 0000 0020 0047 0000 0002 0002 0000 0065 0308
è => 119D 0000 0020 0035 0000 0002 0002 0000 0065 0300
ê => 119D 0000 0020 003C 0000 0002 0002 0000 0065 0302
ē => 119D 0000 0020 005B 0000 0002 0002 0000 0065 0304

e:

eA => 119D 1141 0000 0020 0020 0000 0002 0008 0000 0065 0041
éB => 119D 1157 0000 0020 0032 0020 0000 0002 0002 0008 0000 0065 0301 0042
ëC => 119D 116F 0000 0020 0047 0020 0000 0002 0002 0008 0000 0065 0308 0043
èD => 119D 1182 0000 0020 0035 0020 0000 0002 0002 0008 0000 0065 0300 0044
êE => 119D 119D 0000 0020 003C 0020 0000 0002 0002 0008 0000 0065 0302 0045
ēF => 119D 11D5 0000 0020 005B 0020 0000 0002 0002 0008 0000 0065 0304 0046

e:

è 1 => 119D 0209 1138 0000 0020 0035 0020 0020 0000 0002 0002 0002 0002 0000 0065 0300 0020 0031
ê 5 => 119D 0209 113C 0000 0020 003C 0020 0020 0000 0002 0002 0002 0002 0000 0065 0302 0020 0035
e 2 => 119D 0209 1139 0000 0020 0020 0020 0000 0002 0002 0002 0000 0065 0020 0032
é 4 => 119D 0209 113B 0000 0020 0032 0020 0020 0000 0002 0002 0002 0002 0000 0065 0301 0020 0034
ē 3 => 119D 0209 113A 0000 0020 005B 0020 0020 0000 0002 0002 0002 0002 0000 0065 0304 0020 0033
ë 6 => 119D 0209 113D 0000 0020 0047 0020 0020 0000 0002 0002 0002 0002 0000 0065 0308 0020 0036

che fornisce di nuovo questi tre risultati ordinati:

e
é
è
ê
ë
ē

e

eA
éB
ëC
èD
êE
ēF

e

è 1
e 2
ē 3
é 4
ê 5
ë 6

Ciao patrick Grazie per aver pubblicato queste informazioni dettagliate. Alcune note: 1) È possibile ignorare la pagina di codice 1252. Questo è per i dati VARCHAR(cioè non Unicode), che non viene utilizzato qui. Ecco perché il ēpersonaggio funziona bene. 2) Le informazioni sui "grafici di confronto" sono un po 'obsolete. È per una versione precedente di questa raccolta e non hanno pubblicato nulla dal 2009. 3) La versione Unicode qui non è sicuramente l'ultima (versione 10). La _100_serie Collations è arrivata con SQL 2008, quindi sarebbe Unicode 5.0 o 5.1: unicode.org/standard/versions/#TUS_Earlier_Versions
Solomon Rutzky

Non credo che i allKeys.txt cambiamenti tra la versione Unicode, oltre all'aggiunta di nuovi personaggi, quindi quanto sopra dovrebbe rimanere vero, ma ovviamente potrebbe essere rifatto con i vecchi dati precedenti, mi manca solo l'energia di reinserirci alcune ore. Per quanto riguarda CP1252, era appena arrivato dalla definizione fornita da MS-SQL (non uso questo prodotto da solo).
Patrick Mevzek,

1) Probabilmente non ci sono cambiamenti importanti tra le versioni, ma sono abbastanza sicuro che ci siano correzioni di peso / classificazione, almeno. Ma sì, ottengo certamente i vincoli temporali;) 2) Per quanto riguarda CP1252, ne parlavo perché il concetto di Code Pages non esiste in Unicode. Unicode è un mezzo per non aver mai bisogno di pagine di codice. Il documento MS non è chiaro su questo, ma menziona all'inizio " La tabella codici utilizzata per archiviare dati di caratteri non Unicode ". Hai ragione sul fatto che l'unico personaggio non è in CP1252, ma le Code page non entrano in gioco qui.
Solomon Rutzky,

Sì, non ho mai detto nulla sulla tabella codici relativa a Unicode. È solo la documentazione di MS SQL che afferma che questo nome di confronto funziona con "code page 1252". Probabilmente non ha senso (non per me, ma ancora non per un utente) ma è ciò che è scritto nella documentazione di questo software. Per quanto riguarda la ripetizione del lavoro, sentiti libero di farlo o fornisci semplicemente le modifiche relative all'ordinamento relativo ai personaggi in gioco qui tra Unicode 5 e gli ultimi, se ci sono e se vuoi. Credo che la mia risposta sia così com'è, sia precisa e costruisca i risultati in base all'input, non viceversa.
Patrick Mevzek,

3) re: frase n. 1: anche se riguarda principalmente Unicode, questa domanda è un problema del sistema operativo poiché MS ha implementato le specifiche e potrebbe non aver fatto tutto e / o aver commesso degli errori. Ho trovato 2 bug in .NET riguardo al modo in cui determina la "categoria" o "blocco" in cui si trova un determinato personaggio (stavano identificando erroneamente un piccolo segmento di caratteri). Inoltre, questo è , almeno leggermente, un problema di SQL Server, solo perché SQL Server ha effettivamente un'istantanea di ogni confronto in un determinato momento (per coerenza tra le versioni), quindi potrebbero avere quello che ora è il comportamento specifico di SQL Server.
Solomon Rutzky,

16

Il comportamento che stai vedendo qui è dovuto, in senso generale, al fatto che Unicode Collation Algorithm (UCA) consente un ordinamento multilivello complesso. Più specificamente:

  1. L'ordinamento non è un confronto:

    Determinare se due stringhe sono uguali o diverse è abbastanza semplice (dati una lingua / lingua e un insieme di sensibilità particolari). Ma determinare l'ordine di 2 o più stringhe può essere estremamente complesso.

  2. L'ordinamento viene eseguito in una serie di passaggi, con ogni passaggio applicato all'intera stringa, non carattere per carattere:

    1. Standard: ordina i caratteri di base (indipendentemente dall'accento e dalle differenze tra maiuscole e minuscole)
    2. Se sensibile all'accento, applicare pesi accentati / diacritici
    3. In caso di distinzione tra maiuscole e minuscole, applicare i pesi dell'involucro

Quando si ordina per col1(carattere singolo), si determina innanzitutto che tutti i personaggi hanno lo stesso peso poiché sono tutti " e ". Successivamente, applica i pesi accento / diacritico. Non ci sono differenze di involucro, quindi il terzo passaggio non cambierebbe nulla. Quindi le uniche differenze sono nel passaggio 2, motivo per cui esiste un ordine preferito per quelle righe in base col1.

Quando si ordina per col2(due caratteri), si determina innanzitutto che ogni riga ha un peso diverso poiché entrambi i caratteri vengono utilizzati per determinare il peso dell'ordinamento (ad es. " Ea ", " eb ", ecc.). Successivamente, applica i pesi accento / diacritico. Non ci sono differenze di involucro, quindi il terzo passaggio non cambierebbe nulla. Quindi ci sono differenze nei passaggi 1 e 2 questa volta. Ma poiché le differenze nel passaggio 1 sono già state applicate a ciascuna stringa prima di considerare i pesi del passaggio 2, i pesi del passaggio 2 non hanno alcun effetto sull'ordinamento; si applicherebbero solo se i pesi del passaggio 1 per due o più file fossero uguali.

Il seguente adattamento del codice di esempio dalla domanda illustra, si spera, il comportamento di ordinamento sopra descritto. Ho aggiunto alcune righe aggiuntive e una colonna aggiuntiva per aiutare a mostrare l'impatto del confronto con distinzione tra maiuscole e minuscole (poiché i dati del campione originale sono tutti minuscoli):

IMPOSTARE

USE [tempdb];

-- DROP TABLE dbo.OddSort;
CREATE TABLE dbo.OddSort
(
    id INT IDENTITY(1,1) PRIMARY KEY,
    col1 NVARCHAR(5) COLLATE Latin1_General_100_CS_AS,
    col2 NVARCHAR(5) COLLATE Latin1_General_100_CS_AS,
    col3 NVARCHAR(5) COLLATE Latin1_General_100_CS_AS
);
GO

INSERT dbo.OddSort (col1, col2, col3)
VALUES (N'e', N'eA', N'e A')
     , (N'ê', N'êE', N'ê E')
     , (N'é', N'éH', N'é H')
     , (N'ë', N'ëC', N'ë C')
     , (N'E', N'EG', N'E G')
     , (N'Ë', N'ëh', N'ë h')
     , (N'è', N'èD', N'è D')
     , (N'é', N'éB', N'é B')
     , (N'ë', N'ëH', N'ë H')
     , (N'ē', N'ēF', N'ē F');

TEST 1

SELECT [id], [col1], UNICODE([col1]) AS [CodePoint]
FROM dbo.OddSort 
ORDER BY col1;

Ritorna:

id    col1    CodePoint
1     e       101
5     E       69
8     é       233
3     é       233
7     è       232
2     ê       234
4     ë       235
9     ë       235
6     Ë       203
10    ē       275

Cosa possiamo vedere nei risultati sopra:

  1. Il punto di codice non determina l'ordinamento
  2. I caratteri non accentati vengono ordinati prima dei caratteri accentati (all'interno della stessa lettera: f verrebbe comunque dopo tutti questi). Chiaramente, i pesi di accento vengono applicati prima dei pesi di caso.
  3. Le lettere minuscole vengono ordinate prima delle lettere maiuscole all'interno dello stesso carattere accentato (o non accentato) (ovvero e quindi E , e ë quindi Ë ). Questa personalizzazione viene utilizzata dalla maggior parte delle regole di confronto di Windows, mentre la maggior parte delle regole di confronto di SQL Server ordina prima in maiuscolo.

TEST 2

SELECT [id], [col2]
FROM dbo.OddSort 
ORDER BY col2;

Ritorna:

id    col2
1     eA
8     éB
4     ëC
7     èD
2     êE
10    ēF
5     EG
3     éH
6     ëh
9     ëH

Cosa possiamo vedere nei risultati sopra:

  1. L'ordinamento di primo livello è davvero il personaggio base. Se si trattasse di accenti / segni diacritici, le righe ëC (id = 4), ēF (id = 10) ed EG (id = 5) non sarebbero dove si trovano. Se fosse involucro, la riga EG (id = 5) non sarebbe dove si trova.
  2. L'ordinamento di secondo livello è davvero l'accento / i segni diacritici. Questo spiega perché le ultime tre righe sono éH -> ëh -> ëH invece di ëh -> éH -> ëH (ovvero ID 3 -> 6 -> 9 anziché 6 -> 3 -> 9).
  3. L'ordinamento di terzo livello è davvero l'involucro. Questo è il motivo per cui le ultime 2 righe sono ëh -> ëH , poiché le lettere minuscole vengono ordinate per prime.

TEST 3

SELECT [id], [col3]
FROM dbo.OddSort 
ORDER BY col3;

Ritorna:

id    col3
1     e A
8     é B
4     ë C
7     è D
2     ê E
10    ē F
5     E G
3     é H
6     ë h
9     ë H

Cosa possiamo vedere nei risultati sopra:

  1. L'ordinamento è esattamente lo stesso del Test 2. L'unica differenza nei valori di test qui è che c'è uno spazio tra ogni carattere, eliminando la possibilità di regole contestuali. Quindi, sappiamo che la ragione della differenza nell'ordinamento col2nella domanda è di nuovo dovuta al "Confronto multilivello" e non alla "Sensibilità contestuale".

Note aggiuntive:

  1. Per quanto riguarda ottenere le regole esatte, non è facile come dovrebbe essere. Il problema di ottenere spiegazioni concrete di queste regole è che le regole di ordinamento Unicode, sebbene siano sicuramente documentate, sono una raccomandazione. Spetta ai fornitori, come Microsoft, implementare tali raccomandazioni. Microsoft non ha implementato le raccomandazioni esattamente come indicato nella documentazione Unicode, quindi c'è una disconnessione lì (simile a come né le specifiche HTML o CSS sono implementate in modo completo, né allo stesso modo, tra i fornitori). Quindi, ci sono diverse versioni delle regole di confronto di Windows (si sta utilizzando la versione 100che è uscita con SQL Server 2008) e che è legata a una versione Unicode che è molto più vecchia della versione corrente di Unicode o di quella in demo delle regole di confronto ICUsta usando. Ad esempio, la sezione Novità di SQL Server 2008 Raccolte della documentazione "Supporto regole di confronto e Unicode" per SQL Server 2008 contiene 2 punti molto interessanti su ciò che è "nuovo" nella _100_serie Raccolte:

    1. Tabella dei casi Unicode 5.0.

      Unicode 5.0 è stato pubblicato nel luglio del 2006 (beh, il database dei personaggi è stato rilasciato allora e le specifiche complete sono state seguite alla fine del 2006). La versione attuale è la 10.0, che è stata pubblicata nel giugno del 2017. E dato il modello di rilascio degli ultimi 4 anni, è probabile che la versione 11.0 uscirà a metà 2018.

    2. La ponderazione è stata aggiunta a caratteri precedentemente non ponderati che sarebbero stati paragonati allo stesso modo.

      Quei pesi erano più che probabilmente definiti nello standard Unicode, ma non in questa sua implementazione.

     
    Tuttavia, la documentazione UCA collegata sopra è un buon punto di partenza.

  2. Le chiavi di ordinamento utilizzate da Windows / .NET / SQL Server non sono esattamente le stesse mostrate nello standard Unicode (vedi la risposta di @ Patrick) o implementate nell'ICU . Per vedere cosa usano Windows / .NET / SQL Server, puoi provare il metodo CompareInfo.GetSortKey . Ho creato un UDF SQLCLR per passare questi valori e ottenere la chiave di ordinamento. Si noti che sto usando SQL Server 2017 su Windows 10 con .NET Framework 4.5 - 4.6.1 installato, quindi .NET dovrebbe utilizzare Unicode 6.0.0. Inoltre, Level4 non viene utilizzato per queste stringhe.

    CHAR    L1     L2     L3     L4
    e      0E21
    E      0E21           12
    ë      0E21    13
    Ë      0E21    13     12

    Guardando queste chiavi di ordinamento per il Test 1 e realizzando che i livelli sono ordinati come più colonne all'interno di una ORDER BYclausola (L3 è ordinata all'interno degli stessi valori di L2, che è ordinata all'interno degli stessi valori di L1), dovrebbe illustrare che il motivo del comportamento notato nella domanda è infatti la capacità di ordinamento multilivello di Unicode. Allo stesso modo:

    CHAR       L1         L2       L3       L4
    EG      0E210E25              1212
    éH      0E210E2C      0E      0212
    ëh      0E210E2C      13
    ëH      0E210E2C      13      0212

    Osservando alcune delle chiavi di ordinamento per Test 2, possiamo vedere che i caratteri di base vengono prima ordinati (L1), quindi gli accenti vengono ordinati (L2) e quindi i riquadri vengono ordinati (L3).

  3. Poiché il tipo di dati è NVARCHAR, ci occupiamo solo dei punti di codice Unicode e degli algoritmi di ordinamento, quindi l'uso della UNICODE()funzione in TEST 1. Mentre le pagine di codice sono specificate dalla maggior parte delle regole di confronto, riguardano solo i VARCHARdati. Significato, mentre il codice pagina 1252 è specificato dalla Latin1_General*serie di regole di confronto, che può essere ignorato qui.

  4. I pesi descritti nella tabella degli elementi delle regole di confronto Unicode (DUCET) predefinita ( versione 5.0.0 che dovrebbe essere associata alle _100_serie delle regole di confronto) vanno bene per l'inglese americano, ma non per altre lingue / lingue. Altre lingue devono iniziare con DUCET e quindi applicare le regole di sostituzione specifiche della locale definite dal progetto CLDR (Common Locale Data Repository). Da quello che posso dire, le versioni 1.4 / 1.4.1 sono state rilasciate nel 2006. Per ottenere tali sostituzioni, scaricare il file "core" di CLDR 1.4 tramite http://unicode.org/Public/cldr/1.4.0/core.zip , quindi, in quel file zip, vai alla cartella delle regole di confronto e trova il file XML corrispondente alla locale utilizzata. Tali file contengono solo le sostituzioni e non sono insiemi completi di regole di confronto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.