Tri sensible aux accents


19

Pourquoi ces deux SELECTinstructions aboutissent-elles à un ordre de tri différent?

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 ║ - devrait être 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 ║
╚════╩══════╩══════╝

Réponses:


13

Cette question n'est pas tellement liée aux bases de données mais plutôt à la gestion et aux règles Unicode.

Basé sur https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql Latin1_General_100_CS_AS signifie: "Le classement utilise les règles de tri du dictionnaire général Latin1 et correspond à la page de code 1252 "avec le CS = sensible à la casse et AS = sensible à l'accent ajouté.

Le mappage entre la page de codes Windows 1252 et Unicode ( http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT ) affiche les mêmes valeurs pour tous les caractères avec lesquels nous traitons (sauf e avec macron qui n'existe pas dans le mappage Microsoft, donc aucune idée de ce qu'il fait avec ce cas), nous pouvons donc nous concentrer sur les outils et la terminologie Unicode pour l'instant.

Tout d'abord, faites-nous savoir précisément à quoi nous avons affaire, pour toutes vos cordes:

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'algorithme de classement Unicode est décrit ici: https://www.unicode.org/reports/tr10/

Jetez un œil à la section 1.3 "Sensibilité contextuelle" qui explique que le tri ne peut pas dépendre d'un seul caractère après l'autre car certaines règles sont contextuelles.

Notez également ces points en 1.8:

Le classement n'est pas une propriété des chaînes. L'ordre de classement n'est pas conservé lors des opérations de concaténation ou de sous-chaîne, en général.

Par défaut, l'algorithme utilise trois niveaux entièrement personnalisables. Pour l'écriture latine, ces niveaux correspondent grosso modo à:

alphabetic ordering
diacritic ordering
case ordering.

Mais l'algorithme en lui-même est un peu dense. L'essentiel est le suivant: En bref, l'algorithme de classement Unicode prend une chaîne Unicode d'entrée et une table d'éléments de classement, contenant des données de mappage pour les caractères. Il produit une clé de tri, qui est un tableau d'entiers 16 bits non signés. Deux ou plusieurs clés de tri ainsi produites peuvent ensuite être comparées en binaire pour donner la comparaison correcte entre les chaînes pour lesquelles elles ont été générées.

Vous pouvez afficher les règles de tri latin spécifiques ici: http://developer.mimer.com/collations/charts/latin.htm ou plus directement et spécifiquement pour MS SQL: http://collation-charts.org/mssql/mssql. 0409.1252.Latin1_General_CS_AS.html

Pour le epersonnage, il montre:

e E é É è È ê Ê ë Ë

Cela explique vos résultats lors de la commande, col1sauf que ē n'existe pas dans la page de code 1252, donc je n'ai absolument aucune idée de ce qu'il en fait.

Ou si nous faisons l'algorithme Unicode à la main, en utilisant la valeur de clés de DUCET à http://www.unicode.org/Public/UCA/latest/allkeys.txt :

étape 1: Formulaire de normalisation D, donc chaque cas devient:

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

étape 2, produire des tableaux de classement (recherche dans le fichier 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]

étape 3, Formulaire de tri des clés (pour chaque niveau, prenez chaque valeur dans chaque tableau de classement, puis mettez 0000 comme délimiteur et recommencez pour le niveau suivant)

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

étape 4, Comparer les clés de tri (simple comparaison binaire de chaque valeur une par une): La quatrième valeur suffit pour toutes les trier, donc l'ordre final devient:

e
é
è
ê
ë
ē

De même pour commander sur col2:

étape 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

étape 2: tableaux de classement

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]

étape 3: clés de tri du formulaire

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

étape 4: Comparer les clés de tri: La deuxième valeur suffit pour toutes les trier, et elle est en fait déjà en ordre croissant, donc l'ordre final est en effet:

eA
éB
ëC
èD
êE
ēF

Mise à jour : ajout du troisième cas de Solomon Rutzky, ce qui est plus délicat en raison de l'espace qui permet de nouvelles règles (j'ai choisi le "cas non ignorable"):

étape 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

étape 2, produire des tableaux de classement:

è 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]

étape 3, clés de tri du formulaire:

è 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

étape 4, comparer les clés de tri:

Fondamentalement, la troisième valeur détermine l'ordre, et elle n'est en fait basée que sur le dernier chiffre, donc l'ordre doit être:

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

Deuxième mise à jour basée sur le commentaire de Solomon Rutzky sur les versions Unicode.

J'ai utilisé les allkeys.txtdonnées sur la dernière version d'Unicode à ce moment, c'est-à-dire la version 10.0

Si nous devons plutôt prendre en compte Unicode 5.1 , ce serait: http://www.unicode.org/Public/UCA/5.1.0/allkeys.txt

Je viens de vérifier, pour tous les caractères ci-dessus, les tableaux de classement sont les suivants à la place:

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]

et:

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]

et:

è 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]

qui calcule ensuite les clés de tri suivantes:

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

et:

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

et:

è 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

ce qui donne à nouveau ces trois résultats triés:

e
é
è
ê
ë
ē

et

eA
éB
ëC
èD
êE
ēF

et

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

Salut Patrick. Merci d'avoir publié cette information détaillée. Quelques notes: 1) Vous pouvez ignorer la page de code 1252. Cela concerne les données VARCHAR(c'est-à-dire non Unicode), qui ne sont pas utilisées ici. C'est pourquoi le ēpersonnage fonctionne très bien. 2) L'information "collation-charts" est un peu dépassée. C'est pour une version précédente de ce classement et ils n'ont rien publié depuis 2009. 3) La version Unicode ici n'est certainement pas la dernière (version 10). La _100_série Collations est venue avec SQL 2008, donc ce serait Unicode 5.0 ou 5.1: unicode.org/standard/versions/#TUS_Earlier_Versions
Solomon Rutzky

Je ne pense pas que les allKeys.txt changements entre la version Unicode, en plus de l'ajout de nouveaux personnages, donc ce qui précède devrait rester vrai, mais bien sûr, il pourrait être refait avec les anciennes données précédentes, je manque juste d'énergie pour y mettre encore quelques heures. Quant au CP1252, il venait juste de la définition donnée par MS-SQL (je n'utilise pas moi-même ce produit).
Patrick Mevzek

1) Il n'y a probablement pas de changements majeurs entre les versions, mais je suis à peu près sûr qu'il y a au moins des corrections de poids / classification. Mais oui, j'obtiens certainement les contraintes de temps;) 2) Concernant CP1252, je le mentionnais car le concept de Pages de Code n'existe pas au sein d'Unicode. Unicode est un moyen de ne jamais avoir besoin de pages de codes. Le doc MS n'est certes pas clair à ce sujet, mais il mentionne vers le haut " La page de code utilisée pour stocker les données de caractères non Unicode. ". Vous avez raison de dire que le seul caractère n'est pas dans CP1252, mais les pages de codes n'entrent pas en jeu ici.
Solomon Rutzky

Oui, je n'ai jamais rien dit sur la page de codes liée à Unicode. C'est juste la documentation MS SQL qui dit que ce nom de classement fait le travail avec la "page de code 1252". Cela n'a probablement aucun sens (ce n'est pas le cas pour moi, mais encore une fois, pas un utilisateur), mais c'est ce qui est écrit dans la documentation de ce logiciel. Pour ce qui est de refaire le travail, n'hésitez pas à le faire ou fournissez simplement les changements de tri liés aux personnages en jeu ici entre Unicode 5 et les dernières, s'il y en a et si vous le souhaitez. Je crois que ma réponse est telle qu'elle est, est précise et construit les résultats en fonction de la saisie, et non l'inverse.
Patrick Mevzek

3) re: phrase n ° 1: bien qu'elle concerne principalement Unicode, cette question est un problème de système d'exploitation car MS a implémenté la spécification et n'a peut-être pas tout fait et / ou peut-être fait des erreurs. J'ai trouvé 2 bogues dans .NET concernant la façon dont il détermine la "catégorie" ou le "bloc" dans lequel se trouve un caractère particulier (ils identifiaient mal un petit segment de caractères). En outre, il s'agit , au moins légèrement, d'un problème SQL Server, uniquement parce que SQL Server a effectivement un instantané de chaque classement à un moment donné (pour la cohérence entre les versions), afin qu'ils puissent avoir ce qui est désormais un comportement spécifique à SQL Server.
Solomon Rutzky

16

Le comportement que vous voyez ici est dû, dans un sens général, au fait que l' algorithme de classement Unicode (UCA) permet un tri complexe à plusieurs niveaux. Plus précisement:

  1. Le tri n'est pas une comparaison:

    Déterminer si deux chaînes sont identiques ou différentes est assez simple (étant donné un lieu / une langue particuliers et un ensemble de sensibilités). Mais déterminer l'ordre de 2 chaînes ou plus peut être très complexe.

  2. Le tri se fait en une série d'étapes, chaque étape étant appliquée à la chaîne entière, pas caractère par caractère:

    1. Standard: trier les caractères de base (indépendamment des différences d'accentuation et de casse)
    2. SI sensible à l'accent, appliquer des poids accentués / diacritiques
    3. SI sensible à la casse, appliquer des poids de boîtier

Lorsque vous triez par col1(caractère unique), il détermine d'abord que tous les caractères ont le même poids car ils sont tous " e ". Ensuite, il applique les poids accent / diacritique. Il n'y a pas de différence de boîtier, donc la troisième étape ne changera rien. Ainsi, les seules différences se trouvent à l'étape 2, c'est pourquoi il existe un ordre préféré pour ces lignes en fonction col1.

Lorsque vous triez par col2(deux caractères), il détermine d'abord que chaque ligne a un poids différent puisque les deux caractères sont utilisés pour déterminer le poids du tri (par exemple " ea ", " eb ", etc.). Ensuite, il applique les poids accent / diacritique. Il n'y a pas de différence de boîtier, donc la troisième étape ne changera rien. Il y a donc des différences dans les étapes 1 et 2 cette fois. Mais comme les différences de l'étape 1 ont déjà été appliquées à chaque chaîne avant que les poids de l'étape 2 soient pris en compte, les poids de l'étape 2 n'ont aucun effet sur l'ordre; ils ne s'appliqueraient que si les poids de l'étape 1 pour deux lignes ou plus étaient identiques.

Nous espérons que l'adaptation suivante de l'exemple de code de la question illustre le comportement de tri décrit ci-dessus. J'ai ajouté quelques lignes supplémentaires et une colonne supplémentaire pour aider à montrer l'impact du classement en respectant la casse (puisque les données d'échantillon d'origine sont toutes en minuscules):

INSTALLER

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;

Retour:

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

Ce que nous pouvons voir dans les résultats ci-dessus:

  1. Le point de code ne détermine pas l'ordre de tri
  2. Les caractères non accentués sont triés avant les caractères accentués (dans la même lettre: f viendrait toujours après tout cela). De toute évidence, les pondérations d'accent sont appliquées avant les pondérations de cas.
  3. Les minuscules trient avant les majuscules dans le même caractère accentué (ou non accentué) (c'est-à-dire le e puis E , et le ë puis Ë ). Cette personnalisation est utilisée par la plupart des classements Windows, tandis que la plupart des classements SQL Server trient les majuscules en premier.

TEST 2

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

Retour:

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

Ce que nous pouvons voir dans les résultats ci-dessus:

  1. Le tri de premier niveau est vraiment les caractères de base. S'il s'agissait d'accents / diacritiques, les lignes ëC (id = 4), ēF (id = 10) et EG (id = 5) ne seraient pas là où elles sont. S'il s'agissait d'un boîtier, la ligne EG (id = 5) ne serait pas là où elle se trouve.
  2. Le tri de deuxième niveau est vraiment les accents / diacritiques. Cela explique pourquoi les trois dernières lignes sont éH -> ëh -> ëH au lieu de ëh -> éH -> ëH (c'est-à-dire les ID 3 -> 6 -> 9 au lieu de 6 -> 3 -> 9).
  3. Le tri de troisième niveau est vraiment le boîtier. C'est pourquoi les 2 dernières lignes sont ëh -> ëH , car les minuscules trient en premier.

TEST 3

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

Retour:

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

Ce que nous pouvons voir dans les résultats ci-dessus:

  1. L'ordre de tri est exactement le même que dans le test 2. La seule différence dans les valeurs de test ici est qu'il y a un espace entre chaque caractère, supprimant la possibilité de règles contextuelles. Par conséquent, nous savons que la raison de la différence d'ordre de tri col2dans la question est à nouveau due à la "comparaison à plusieurs niveaux" et non à la "sensibilité contextuelle".

Notes complémentaires:

  1. En ce qui concerne l'obtention des règles exactes, ce n'est pas aussi facile qu'il devrait l'être. Le problème pour obtenir des explications concrètes de ces règles est que les règles de tri Unicode, bien que clairement documentées, sont une recommandation. Il appartient aux fournisseurs, tels que Microsoft, de mettre en œuvre ces recommandations. Microsoft n'a pas implémenté les recommandations exactement comme indiqué dans la documentation Unicode, il y a donc une déconnexion (similaire à la façon dont ni les spécifications HTML ou CSS ne sont implémentées aussi complètement, ni même de la même manière, entre les fournisseurs). Ensuite, il existe différentes versions des classements Windows (vous utilisez une version 100fournie avec SQL Server 2008) et qui est liée à une version Unicode beaucoup plus ancienne que la version actuelle d'Unicode ou de la démonstration ICU Collationutilise. Par exemple, la section Nouveautés de SQL Server 2008 Collations de la documentation "Collation and Unicode Support" pour SQL Server 2008 présente 2 points très intéressants sur les nouveautés de la _100_série Collations:

    1. Table de cas Unicode 5.0.

      Unicode 5.0 a été publié en juillet 2006 (enfin, la base de données de personnages a été publiée à ce moment-là, et la spécification complète a suivi fin 2006). La version actuelle est 10.0 qui a été publiée en juin 2017. Et compte tenu du modèle de publication des 4 dernières années, il est probable que la version 11.0 sera disponible mi-2018.

    2. Une pondération a été ajoutée aux caractères précédemment non pondérés qui se seraient comparés également.

      Ces poids étaient plus que probablement définis dans la norme Unicode, mais pas dans sa mise en œuvre.

     
    Pourtant, la documentation UCA liée ci-dessus est un bon point de départ.

  2. Les clés de tri utilisées par Windows / .NET / SQL Server ne sont pas exactement les mêmes que celles affichées dans la norme Unicode (voir la réponse de @ Patrick) ou implémentées dans l' ICU . Pour voir ce que Windows / .NET / SQL Server utilise, vous pouvez essayer la méthode CompareInfo.GetSortKey . J'ai créé un UDF SQLCLR pour transmettre ces valeurs et obtenir la clé de tri. Veuillez noter que j'utilise SQL Server 2017 sur Windows 10 avec .NET Framework 4.5 - 4.6.1 installé, donc .NET devrait utiliser Unicode 6.0.0. De plus, Level4 n'est pas utilisé pour ces chaînes.

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

    En regardant ces clés de tri pour le test 1 et en réalisant que les niveaux sont triés comme plusieurs colonnes dans une ORDER BYclause (L3 est trié selon les mêmes valeurs de L2, qui est trié selon les mêmes valeurs de L1), devrait illustrer que la raison du comportement noté dans la question est en fait la capacité de tri à plusieurs niveaux d'Unicode. Également:

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

    En regardant certaines des clés de tri pour le test 2, nous pouvons voir que les caractères de base sont d'abord triés (L1), puis les accents sont triés (L2), puis le boîtier est trié (L3).

  3. Comme le type de données est NVARCHAR, nous ne nous intéressons qu'aux points de code Unicode et aux algorithmes de tri, d'où l'utilisation de la UNICODE()fonction dans TEST 1. Bien que les pages de code soient spécifiées par la plupart des classements, elles ne concernent que les VARCHARdonnées. Signification, alors que la page de codes 1252 est spécifiée par la Latin1_General*série de classements, cela peut être ignoré ici.

  4. Les pondérations décrites dans la table d'éléments de classement Unicode par défaut (DUCET) ( version 5.0.0 qui devrait correspondre aux classements de la _100_série) conviennent pour l'anglais américain, mais pas pour les autres paramètres régionaux / langues. D'autres langues doivent commencer par le DUCET, puis appliquer des règles de substitution spécifiques aux paramètres régionaux, telles que définies par le projet Common Locale Data Repository (CLDR). D'après ce que je peux dire, les versions 1.4 / 1.4.1 ont été publiées en 2006. Pour obtenir ces remplacements, téléchargez le fichier "core" CLDR 1.4 via http://unicode.org/Public/cldr/1.4.0/core.zip , puis, dans ce fichier zip, accédez au dossier de classement et recherchez le fichier XML correspondant aux paramètres régionaux utilisés. Ces fichiers contiennent uniquement les remplacements et ne sont pas des ensembles complets de règles de classement.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.