Akzentempfindliche Sortierung

19

Warum führen diese beiden SELECTAnweisungen zu einer unterschiedlichen Sortierreihenfolge?

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 ║ - sollte id 3 sein?
║ 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 ║
╚════╩══════╩══════╝
Aram
quelle

Antworten:

13

Diese Frage bezieht sich nicht auf Datenbanken, sondern eher auf die Handhabung und Regeln von Unicode.

Basierend auf https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql Latin1_General_100_CS_AS bedeutet: „Sortierungs die Latin1 Allgemeine Wörterbuch verwendet Regeln und Karten - Codepage Sortierung 1252 "mit dem zusätzlichen CS = Case Sensitive und AS = Accent Sensitive.

Die Zuordnung zwischen Windows-Codepage 1252 und Unicode ( http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT ) zeigt für alle Zeichen, mit denen wir zu tun haben, die gleichen Werte an (mit Ausnahme von e mit macron) Das gibt es in Microsoft Mapping nicht, also keine Ahnung, was es in diesem Fall tut. Daher können wir uns vorerst auf Unicode-Tools und -Terminologie konzentrieren.

Lassen Sie uns zunächst genau wissen, um was es sich bei all Ihren Saiten handelt:

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

Der Unicode-Kollatierungsalgorithmus wird hier beschrieben: https://www.unicode.org/reports/tr10/

Schauen Sie sich Abschnitt 1.3 "Kontextsensitivität" an, in dem erklärt wird, dass die Sortierung nicht nur von einem Zeichen nach dem anderen abhängen kann, da einige Regeln kontextsensitiv sind.

Beachten Sie auch diese Punkte in 1.8:

Kollatierung ist keine Eigenschaft von Zeichenfolgen. Die Sortierreihenfolge bleibt im Allgemeinen bei Verkettungs- oder Teilzeichenfolgenoperationen nicht erhalten.

Standardmäßig verwendet der Algorithmus drei vollständig anpassbare Ebenen. Für die lateinische Schrift entsprechen diese Ebenen ungefähr:

alphabetic ordering
diacritic ordering
case ordering.

Aber der Algorithmus an sich ist ein bisschen dicht. Das Wesentliche dabei ist: Kurz gesagt, der Unicode- Kollatierungsalgorithmus verwendet eine Eingabe-Unicode-Zeichenfolge und eine Kollatierungselementtabelle, die Zuordnungsdaten für Zeichen enthält. Es wird ein Sortierschlüssel erzeugt, bei dem es sich um ein Array von 16-Bit-Ganzzahlen ohne Vorzeichen handelt. Zwei oder mehr so ​​erzeugte Sortierschlüssel können dann binär verglichen werden, um den richtigen Vergleich zwischen den Zeichenfolgen zu erhalten, für die sie erzeugt wurden.

Sie können die spezifischen lateinischen Sortierregeln hier anzeigen: http://developer.mimer.com/collations/charts/latin.htm oder direkter und spezifischer für MS SQL: http://collation-charts.org/mssql/mssql. 0409.1252.Latin1_General_CS_AS.html

Für den eCharakter zeigt es:

e E é É è È ê Ê ë Ë

Dies erklärt Ihre Ergebnisse bei der Bestellung auf, col1außer dass ē in Codepage 1252 nicht vorhanden ist, so dass ich absolut keine Ahnung habe, was es damit macht.

Wenn Sie den Unicode-Algorithmus von Hand ausführen, verwenden Sie den Schlüsselwert von DUCET unter http://www.unicode.org/Public/UCA/latest/allkeys.txt :

Schritt 1: Normalisierungsform D, so wird jeder Fall:

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

Schritt 2, Erstellen von Kollatierungsarrays (Nachschlagen in der Datei 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]

Schritt 3, Formularsortierschlüssel (für jede Ebene nehmen Sie jeden Wert in jedes Kollatierungsarray, setzen Sie dann 0000 als Trennzeichen und beginnen Sie erneut mit der nächsten Ebene)

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

Schritt 4, Sortierschlüssel vergleichen (einfacher binärer Vergleich jedes Wertes nacheinander): Der vierte Wert reicht aus, um alle zu sortieren, sodass die endgültige Reihenfolge wie folgt lautet:

e
é
è
ê
ë
ē

In der gleichen Weise für die Bestellung auf col2:

Schritt 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

Schritt 2: Sortierreihen

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]

Schritt 3: Formularsortierschlüssel

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

Schritt 4: Sortierschlüssel vergleichen: Der zweite Wert reicht aus, um alle zu sortieren, und ist in der Tat bereits in aufsteigender Reihenfolge. Die endgültige Reihenfolge lautet also in der Tat:

eA
éB
ëC
èD
êE
ēF

Update : Hinzufügen des dritten Falles von Solomon Rutzky, der wegen des Platzes, der neue Regeln ermöglicht, schwieriger ist (ich habe den "nicht ignorierbaren Fall" gewählt):

Schritt 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

Schritt 2, Erstellen von Kollatierungsarrays:

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

Schritt 3, Formularsortierschlüssel:

è 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

Schritt 4, Sortierschlüssel vergleichen:

Grundsätzlich bestimmt der dritte Wert die Reihenfolge, und er basiert tatsächlich nur auf der letzten Ziffer, daher sollte die Reihenfolge folgendermaßen lauten:

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

Zweites Update basierend auf Solomon Rutzkys Kommentar zu Unicode-Versionen.

Ich habe allkeys.txtzu diesem Zeitpunkt die Daten der neuesten Unicode-Version verwendet, also Version 10.0

Wenn wir stattdessen Unicode 5.1 berücksichtigen müssen , wäre dies: http://www.unicode.org/Public/UCA/5.1.0/allkeys.txt

Ich habe gerade überprüft, dass für alle oben genannten Zeichen die Sortierreihen die folgenden sind:

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]

und:

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]

und:

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

die dann zu folgenden Sortierschlüsseln rechnen:

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

und:

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

und:

è 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

was wiederum diese drei sortierten Ergebnisse ergibt:

e
é
è
ê
ë
ē

und

eA
éB
ëC
èD
êE
ēF

und

è 1
e 2
ē 3
é 4
ê 5
ë 6
Patrick Mevzek
quelle
Hallo Patrick. Vielen Dank für die Veröffentlichung dieser detaillierten Informationen. Einige Anmerkungen: 1) Sie können Codepage 1252 ignorieren. Dies gilt für VARCHAR(dh Nicht-Unicode-) Daten, die hier nicht verwendet werden. Das ist der Grund, warum der ēCharakter gut funktioniert. 2) Die Informationen zu "Kollatierungsdiagrammen" sind etwas veraltet. Es ist für eine frühere Version dieser Sammlung und sie haben seit 2009 nichts mehr gepostet. 3) Die Unicode-Version hier ist definitiv nicht die neueste (Version 10). Die _100_Serien-Kollatierungen wurden mit SQL 2008 ausgeliefert, dies wäre also Unicode 5.0 oder 5.1: unicode.org/standard/versions/#TUS_Earlier_Versions
Solomon Rutzky
Ich denke nicht, dass die allKeys.txt Änderungen zwischen der Unicode-Version, außer dem Hinzufügen neuer Zeichen, so dass das oben Gesagte wahr bleiben sollte, aber natürlich könnte es mit den vorherigen alten Daten wiederholt werden, mir fehlt nur die Energie, einige Stunden erneut hinein zu stecken. Der CP1252 stammt nur aus der Definition von MS-SQL (ich verwende dieses Produkt nicht selbst).
Patrick Mevzek
1) Es gibt wahrscheinlich keine größeren Änderungen zwischen den Versionen, aber ich bin mir ziemlich sicher, dass es zumindest Korrekturen in Bezug auf Gewicht und Klassifizierung gibt. Aber ja, ich habe sicherlich die zeitlichen Einschränkungen;) 2) In Bezug auf CP1252 erwähnte ich dies, weil das Konzept der Codepages in Unicode nicht existiert. Unicode ist ein Mittel, um niemals Codepages zu benötigen. Das MS-Dokument ist diesbezüglich zwar unklar, erwähnt jedoch oben " Die Codepage, die zum Speichern von Nicht-Unicode-Zeichendaten verwendet wird ". Sie haben Recht, dass das eine Zeichen nicht in CP1252 enthalten ist, aber hier kommen keine Codepages ins Spiel.
Solomon Rutzky
Ja, ich habe nie etwas über Unicode-Codeseiten gesagt. Es ist nur die MS SQL-Dokumentation, die besagt, dass dieser Kollatierungsname die Arbeit mit "Codepage 1252" erledigt. Es macht wahrscheinlich keinen Sinn (es ist nicht für mich, aber auch nicht für einen Benutzer), aber es ist das, was in der Dokumentation dieser Software geschrieben ist. Wenn Sie den Job wiederholen möchten, können Sie dies tun oder einfach die Änderungen bezüglich der Sortierung in Bezug auf die im Spiel befindlichen Zeichen zwischen Unicode 5 und der neuesten Version angeben, sofern vorhanden und gewünscht. Ich glaube, meine Antwort ist so, wie sie ist, genau und baut die Ergebnisse auf den Eingaben auf, nicht auf der anderen Seite.
Patrick Mevzek
3) Zu Satz 1: Während es sich hauptsächlich um Unicode handelt, handelt es sich bei dieser Frage um ein Betriebssystemproblem, da MS die Spezifikation implementiert hat und möglicherweise nicht alles getan hat und / oder einige Fehler gemacht hat. Ich habe in .NET zwei Fehler gefunden, die sich darauf beziehen, wie die "Kategorie" oder "Block" eines bestimmten Zeichens bestimmt wird (sie haben ein kleines Segment von Zeichen falsch identifiziert). Außerdem handelt es sich zumindest geringfügig um ein SQL Server-Problem, nur weil SQL Server zu einem bestimmten Zeitpunkt (aus Gründen der Konsistenz zwischen den Versionen) eine Momentaufnahme der einzelnen Sortierungen hat, sodass sie möglicherweise ein SQL Server-spezifisches Verhalten aufweisen.
Solomon Rutzky
16

Das Verhalten, das Sie hier sehen, ist im Allgemeinen auf die Tatsache zurückzuführen, dass der Unicode-Kollatierungsalgorithmus (Unicode Collation Algorithm, UCA) eine komplexe mehrstufige Sortierung ermöglicht. Genauer:

  1. Sortieren ist kein Vergleich:

    Es ist ziemlich einfach zu bestimmen, ob zwei Zeichenfolgen gleich oder verschieden sind (unter Berücksichtigung eines bestimmten Gebietsschemas / einer bestimmten Sprache und einer Reihe von Empfindlichkeiten). Die Bestimmung der Reihenfolge von zwei oder mehr Zeichenfolgen kann jedoch sehr komplex sein.

  2. Die Sortierung erfolgt in einer Reihe von Schritten, wobei jeder Schritt auf die gesamte Zeichenfolge angewendet wird und nicht zeichenweise:

    1. Standard: Basiszeichen sortieren (unabhängig von Akzent- und Groß- / Kleinschreibung)
    2. WENN Akzentempfindlich, Akzent / diakritische Gewichte anwenden
    3. WENN Groß- und Kleinschreibung beachtet wird, müssen die Gehäusegewichte angewendet werden

Wenn Sie nach col1(einzelnes Zeichen) sortieren , wird zuerst festgestellt, dass alle Zeichen dasselbe Gewicht haben, da sie alle " e " sind. Als nächstes werden die Akzent- / diakritischen Gewichte angewendet. Es gibt keine Unterschiede in der Gehäuseform, sodass der dritte Schritt nichts ändern würde. Die einzigen Unterschiede bestehen also in Schritt 2, weshalb es für diese Zeilen eine bevorzugte Reihenfolge gibt, die auf basiert col1.

Wenn Sie nach col2(zwei Zeichen) sortieren , wird zunächst festgestellt, dass jede Zeile ein unterschiedliches Gewicht hat, da beide Zeichen zum Bestimmen des Sortiergewichts verwendet werden (z. B. " ea ", " eb " usw.). Als nächstes werden die Akzent- / diakritischen Gewichte angewendet. Es gibt keine Unterschiede in der Gehäuseform, sodass der dritte Schritt nichts ändern würde. Diesmal gibt es also Unterschiede in den Schritten 1 und 2. Da die Unterschiede in Schritt 1 jedoch bereits auf jede Zeichenfolge angewendet wurden, bevor die Gewichte von Schritt 2 berücksichtigt wurden, haben die Gewichte aus Schritt 2 keine Auswirkungen auf die Reihenfolge. Sie gelten nur, wenn die Gewichte aus Schritt 1 für zwei oder mehr Zeilen gleich sind.

Die folgende Anpassung des Beispielcodes aus der Frage veranschaulicht hoffentlich das oben beschriebene Sortierverhalten. Ich habe einige zusätzliche Zeilen und eine zusätzliche Spalte hinzugefügt, um zu veranschaulichen, wie sich die Sortierung auf die Groß- und Kleinschreibung auswirkt (da die ursprünglichen Beispieldaten nur Kleinbuchstaben enthalten):

INSTALLIEREN

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;

Kehrt zurück:

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

Was wir in den Ergebnissen oben sehen können:

  1. Der Codepunkt bestimmt nicht die Sortierreihenfolge
  2. Die nicht akzentuierten Zeichen werden vor den akzentuierten Zeichen sortiert (innerhalb desselben Buchstabens: f würde immer noch nach all diesen kommen). Es ist klar, dass Akzentgewichte vor Fallgewichten angewendet werden.
  3. Kleinbuchstaben werden vor Großbuchstaben innerhalb desselben akzentuierten (oder nicht akzentuierten) Zeichens sortiert (dh das e dann E und das ë dann Ë ). Diese Anpassung wird von den meisten Windows-Kollatierungen verwendet, während die meisten SQL Server-Kollatierungen zuerst in Großbuchstaben sortiert werden.

TEST 2

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

Kehrt zurück:

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

Was wir in den Ergebnissen oben sehen können:

  1. Die Sortierung der ersten Ebene ist wirklich das Grundzeichen. Wenn es sich um Akzente / diakritische Zeichen handeln würde , wären die Zeilen ëC (id = 4), ēF (id = 10) und EG (id = 5) nicht dort, wo sie sich befinden. Wenn es ein Gehäuse wäre, wäre die EG- Zeile (id = 5) nicht dort, wo sie ist.
  2. Second-Level-Sortierung ist wirklich die Akzente / Diakritika. Dies erklärt, warum die letzten drei Zeilen éH -> ëh -> ëH anstelle von ëh -> éH -> ëH lauten (dh IDs 3 -> 6 -> 9 anstelle von 6 -> 3 -> 9).
  3. Third-Level-Sortierung ist wirklich das Gehäuse. Aus diesem Grund lauten die letzten beiden Zeilen ëh -> ëH , da Kleinbuchstaben zuerst sortiert werden.

TEST 3

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

Kehrt zurück:

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

Was wir in den Ergebnissen oben sehen können:

  1. Die Sortierreihenfolge ist genau die gleiche wie in Test 2. Der einzige Unterschied bei den Testwerten besteht darin, dass zwischen den einzelnen Zeichen ein Leerzeichen eingefügt wird, wodurch die Möglichkeit von Kontextregeln ausgeschlossen wird. Daher wissen wir, dass der Grund für die unterschiedliche Sortierreihenfolge col2in der Frage wieder auf "Mehrstufiger Vergleich" und nicht auf "Kontextsensitivität" zurückzuführen ist.

Zusätzliche Bemerkungen:

  1. Bezüglich der genauen Regeln ist das nicht so einfach, wie es sein sollte. Das Problem beim Abrufen konkreter Erklärungen zu diesen Regeln besteht darin, dass die Unicode-Sortierregeln, obwohl sie eindeutig dokumentiert sind, eine Empfehlung darstellen. Es liegt an Anbietern wie Microsoft, diese Empfehlungen umzusetzen. Microsoft hat die Empfehlungen nicht genau so implementiert, wie in der Unicode-Dokumentation angegeben, sodass es dort zu einer Unterbrechung kommt (ähnlich wie weder die HTML- noch die CSS-Spezifikationen von Anbietern vollständig noch auf dieselbe Weise implementiert werden). Dann gibt es verschiedene Versionen der Windows-Kollatierungen (Sie verwenden 100die mit SQL Server 2008 gelieferte Version), die an eine Unicode-Version gebunden sind, die viel älter ist als die aktuelle Unicode-Version oder die Version, die verwendet ICU-Kollatierungsdemobenutzt. DerNeuerungen in SQL Server 2008-Kollatierungen Der Abschnitt "Kollatierungs- und Unicode-Unterstützung" in der Dokumentation zu SQL Server 2008 enthält zwei sehr interessante Punkte zu den Neuerungen in der _100_Reihe "Kollatierungen":

    1. Unicode 5.0-Falltabelle.

      Unicode 5.0 wurde im Juli 2006 veröffentlicht (nun, die Charakterdatenbank wurde dann veröffentlicht und die vollständige Spezifikation folgte Ende 2006). Die aktuelle Version ist 10.0 und wurde im Juni 2017 veröffentlicht. Angesichts des Veröffentlichungsmusters der letzten 4 Jahre ist es wahrscheinlich, dass die Version 11.0 Mitte 2018 veröffentlicht wird.

    2. Zuvor nicht gewichteten Zeichen, die gleichermaßen verglichen worden wären, wurde eine Gewichtung hinzugefügt.

      Diese Gewichte wurden höchstwahrscheinlich im Unicode-Standard definiert, jedoch nicht in dieser Implementierung.

     
    Die oben verlinkte UCA-Dokumentation ist dennoch ein guter Ausgangspunkt.

  2. Sortierschlüssel, die von Windows / .NET / SQL Server verwendet werden, stimmen nicht genau mit denen überein, die im Unicode-Standard (siehe @ Patricks Antwort) oder auf der Intensivstation implementiert sind . Mit der CompareInfo.GetSortKey-Methode können Sie die Verwendung von Windows / .NET / SQL Server überprüfen . Ich habe eine SQLCLR-UDF erstellt, um diese Werte zu übergeben und den Sortierschlüssel zu erhalten. Bitte beachten Sie, dass ich SQL Server 2017 unter Windows 10 mit installiertem .NET Framework 4.5 - 4.6.1 verwende. Daher sollte .NET Unicode 6.0.0 verwenden. Außerdem wird Level4 für diese Zeichenfolgen nicht verwendet.

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

    Wenn Sie sich diese Sortierschlüssel für Test 1 ansehen und feststellen, dass die Ebenen in einer ORDER BYKlausel wie mehrere Spalten sortiert sind (L3 wird in denselben Werten von L2 sortiert, die in denselben Werten von L1 sortiert sind), sollte dies den Grund für das Verhalten verdeutlichen In der Frage ist in der Tat die mehrstufige Sortierfähigkeit von Unicode vermerkt. Gleichfalls:

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

    Wenn wir uns einige der Sortierschlüssel für Test 2 ansehen, sehen wir, dass die Basiszeichen zuerst sortiert werden (L1), dann die Akzente sortiert werden (L2) und dann die Groß- / Kleinschreibung sortiert wird (L3).

  3. Da es sich bei dem Datentyp NVARCHARum Unicode-Codepunkte und Sortieralgorithmen handelt, wird die UNICODE()Funktion in TEST 1 verwendet. Codepages werden zwar von den meisten Sortierungen angegeben, beziehen sich jedoch nur auf VARCHARDaten. Das heißt, während Codepage 1252 durch die Latin1_General*Reihe der Kollatierungen angegeben wird, kann dies hier ignoriert werden.

  4. Die in der Standard-Unicode-Kollatierungselementtabelle (DUCET) ( Version 5.0.0, die den _100_Serienkollatierungen entsprechen sollte ) beschriebenen Gewichtungen sind für US-Englisch in Ordnung, jedoch nicht für andere Gebietsschemata / Sprachen. Andere Sprachen müssen beginnen mit dem Ducet und dann gelten länderspezifische Überschreibung Regeln wie definiert durch die Common Locale Data Repository (CLDR) Projekt. Soweit ich weiß, wurden die Versionen 1.4 / 1.4.1 im Jahr 2006 veröffentlicht. Um diese Außerkraftsetzungen zu erhalten, laden Sie die "Core" -Datei für CLDR 1.4 über http://unicode.org/Public/cldr/1.4.0/core.zip herunter Wechseln Sie dann in dieser ZIP-Datei zum Kollatierungsordner und suchen Sie die XML-Datei, die dem verwendeten Gebietsschema entspricht. Diese Dateien enthalten nur die Außerkraftsetzungen und sind keine vollständigen Sätze von Kollatierungsregeln.

Solomon Rutzky
quelle