Sortir Aksen Sensitif

19

Mengapa kedua SELECTpernyataan ini menghasilkan urutan yang berbeda?

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 ║ - harus berupa 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 ║
╚════╩══════╩══════╝
Aram
sumber

Jawaban:

13

Pertanyaan ini tidak begitu terkait dengan database tetapi lebih pada penanganan dan aturan Unicode.

Berdasarkan https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql Latin1_General_100_CS_AS berarti: "Collation menggunakan kamus umum Latin yang menyortir aturan dan peta ke halaman kode 1252 "dengan tambahan CS = Case Sensitive dan AS = Accent Sensitive.

Pemetaan antara kode Windows halaman 1252 dan Unicode ( http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT ) menunjukkan nilai yang sama untuk semua karakter yang kita hadapi (kecuali e dengan macron yang tidak ada dalam pemetaan Microsoft, jadi tidak tahu apa fungsinya dengan kasus ini), jadi kita dapat berkonsentrasi pada alat dan terminologi Unicode untuk saat ini.

Pertama, beri tahu kami apa yang kami hadapi, untuk semua hal:

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

Algoritma Collation Unicode dijelaskan di sini: https://www.unicode.org/reports/tr10/

Lihat bagian 1.3 "Sensitivitas Kontekstual" yang menjelaskan bahwa penyortiran tidak dapat bergantung hanya pada satu karakter setelah yang lain karena beberapa aturan sensitif terhadap konteks.

Perhatikan juga poin-poin ini di 1.8:

Collation bukan milik string. Urutan collation tidak diawetkan di bawah operasi concatenation atau substring, secara umum.

Secara default, algoritma ini menggunakan tiga level yang sepenuhnya dapat disesuaikan. Untuk skrip Latin, level-level ini secara kasar berhubungan dengan:

alphabetic ordering
diacritic ordering
case ordering.

Tetapi algoritme itu sendiri agak padat. Intinya adalah: Secara singkat dinyatakan, Algoritma Collation Unicode mengambil string Unicode input dan Tabel Elemen Collation, yang berisi data pemetaan untuk karakter. Ini menghasilkan semacam kunci, yang merupakan array bilangan bulat 16-bit yang tidak ditandatangani. Dua atau lebih kunci sortir yang dihasilkan kemudian dapat dibandingkan biner untuk memberikan perbandingan yang benar antara string yang dihasilkan.

Anda dapat melihat aturan penyortiran Latin khusus di sini: http://developer.mimer.com/collations/charts/latin.htm atau lebih langsung dan khusus untuk MS SQL: http://collation-charts.org/mssql/mssql. 0409.1252.Latin1_General_CS_AS.html

Untuk ekarakter yang ditampilkan:

e E é É è È ê Ê ë Ë

Ini menjelaskan hasil Anda ketika memesan, col1kecuali bahwa ē tidak ada di halaman kode 1252, jadi saya sama sekali tidak tahu apa fungsinya.

Atau jika kita melakukan algoritma Unicode dengan tangan, menggunakan nilai kunci DUCET di http://www.unicode.org/Public/UCA/latest/allkeys.txt :

langkah 1: Normalisasi bentuk D, sehingga setiap kasus menjadi:

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

langkah 2, Menghasilkan array susunan (pencarian dalam 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]

langkah 3, Bentuk kunci sortir (untuk setiap level, ambil setiap nilai di dalam setiap susunan susunan, lalu masukkan 0000 sebagai pembatas dan mulai lagi untuk level berikutnya)

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

langkah 4, Bandingkan tombol sortir (perbandingan biner sederhana dari setiap nilai satu per satu): Nilai keempat cukup untuk mengurutkan semuanya, sehingga urutan terakhir menjadi:

e
é
è
ê
ë
ē

Dengan cara yang sama untuk memesan pada col2:

langkah 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

langkah 2: Susunan susunan

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]

langkah 3: Formulir kunci sortir

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

langkah 4: Bandingkan tombol sortir: Nilai kedua sudah cukup untuk menyortir semuanya, dan sebenarnya sudah dalam urutan yang meningkat, sehingga urutan terakhirnya memang:

eA
éB
ëC
èD
êE
ēF

Pembaruan : menambahkan Solomon Rutzky kasus ketiga, yang lebih sulit karena ruang yang memungkinkan aturan baru (saya memilih "kasus yang tidak dapat diabaikan"):

langkah 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

langkah 2, Menghasilkan susunan susunan:

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

langkah 3, Formulir kunci sortir:

è 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

langkah 4, Bandingkan tombol sortir:

Pada dasarnya nilai ketiga menentukan urutan, dan sebenarnya hanya berdasarkan pada digit terakhir, sehingga urutannya harus:

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

Pembaruan kedua berdasarkan komentar Solomon Rutzky tentang versi Unicode.

Saya menggunakan allkeys.txtdata tentang versi Unicode terbaru saat ini, yaitu versi 10.0

Jika kita perlu mempertimbangkan Unicode 5.1 , ini akan menjadi: http://www.unicode.org/Public/UCA/5.1.0/allkeys.txt

Saya baru saja memeriksa, untuk semua karakter di atas, susunan susunan adalah sebagai berikut:

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]

dan:

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]

dan:

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

yang kemudian menghitung kunci penyortiran berikut:

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

dan:

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

dan:

è 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

yang sekali lagi memberikan tiga hasil ini:

e
é
è
ê
ë
ē

dan

eA
éB
ëC
èD
êE
ēF

dan

è 1
e 2
ē 3
é 4
ê 5
ë 6
Patrick Mevzek
sumber
Hai Patrick. Terima kasih telah mengirim info terperinci ini. Beberapa catatan: 1) Anda dapat mengabaikan Kode Page 1252. Itu untuk VARCHAR(yaitu non-Unicode) data, yang tidak digunakan di sini. Itu sebabnya ēkarakter bekerja dengan baik. 2) Info "collation-charts" agak ketinggalan jaman. Ini untuk versi sebelumnya dari Collation ini dan mereka belum memposting apapun sejak 2009. 3) Versi Unicode di sini jelas bukan yang terbaru (Versi 10). The _100_Seri Collations datang dengan SQL 2008, jadi ini akan menjadi Unicode 5.0 atau 5.1: unicode.org/standard/versions/#TUS_Earlier_Versions
Solomon Rutzky
Saya tidak berpikir allKeys.txt perubahan antara versi Unicode, selain penambahan karakter baru, jadi di atas harus tetap benar tetapi tentu saja bisa diulang dengan data lama sebelumnya, saya hanya kekurangan energi untuk menempatkan lagi beberapa jam ke dalamnya. Adapun CP1252 itu hanya berasal dari definisi yang diberikan oleh MS-SQL (saya tidak menggunakan produk ini sendiri).
Patrick Mevzek
1) Mungkin tidak ada perubahan besar antara versi, tapi saya cukup yakin bahwa ada koreksi bobot / klasifikasi, paling tidak. Tapi ya, saya pasti mendapatkan batasan waktu;) 2) Mengenai CP1252, saya menyebutkannya karena konsep Halaman Kode tidak ada dalam Unicode. Unicode adalah cara untuk tidak pernah membutuhkan halaman kode. Dokumen MS memang tidak jelas dalam hal ini, tetapi disebutkan di bagian atas " Halaman kode yang digunakan untuk menyimpan data karakter non-Unicode. ". Anda benar bahwa satu karakter tidak ada dalam CP1252, tetapi Halaman Kode tidak ikut bermain di sini.
Solomon Rutzky
Ya, saya tidak pernah mengatakan apa pun tentang halaman kode yang terkait dengan Unicode. Hanya dokumentasi MS SQL yang mengatakan bahwa nama pemeriksaan ini berfungsi dengan "kode halaman 1252". Mungkin tidak masuk akal (Itu tidak bagi saya, tapi sekali lagi, bukan pengguna itu) tetapi itulah yang tertulis dalam dokumentasi perangkat lunak ini. Sedangkan untuk mengulang pekerjaan, jangan ragu untuk melakukannya atau hanya memberikan perubahan tentang penyortiran yang terkait dengan karakter yang bermain di sini antara Unicode 5 dan terbaru, jika ada dan jika Anda mau. Saya percaya jawaban saya benar, tepat dan membangun hasil berdasarkan input, bukan sebaliknya.
Patrick Mevzek
3) re: kalimat # 1: sementara kebanyakan tentang Unicode, pertanyaan ini adalah masalah OS karena MS mengimplementasikan spesifikasi dan mungkin tidak melakukan semuanya dan / atau mungkin telah membuat beberapa kesalahan. Saya memang menemukan 2 bug di .NET mengenai bagaimana ia menentukan "kategori" atau "blok" di mana karakter tertentu berada (mereka salah mengidentifikasi segmen kecil karakter). Juga, ini adalah , setidaknya sedikit, masalah SQL Server, hanya karena SQL Server memiliki efektif snapshot dari masing-masing Terbit pada titik waktu (untuk konsistensi antara versi), sehingga mereka bisa memiliki apa yang sekarang SQL perilaku Server-spesifik.
Solomon Rutzky
16

Perilaku yang Anda lihat di sini disebabkan, dalam arti umum, oleh fakta bahwa Algoritma Kolom Unicode (UCA) memungkinkan penyortiran multi-level yang kompleks. Lebih spesifik:

  1. Penyortiran bukan Perbandingan:

    Menentukan apakah dua string sama atau berbeda cukup lurus ke depan (diberikan lokal / bahasa tertentu dan serangkaian sensitivitas). Tetapi menentukan urutan 2 string atau lebih bisa sangat kompleks.

  2. Penyortiran dilakukan dalam serangkaian langkah, dengan setiap langkah diterapkan ke seluruh string, bukan karakter demi karakter:

    1. Standar: mengurutkan karakter dasar (terlepas dari aksen dan perbedaan huruf)
    2. JIKA peka-aksen, terapkan bobot aksen / diakritik
    3. JIKA Peka terhadap huruf besar-kecil, gunakan bobot casing

Saat Anda mengurutkan berdasarkan col1(karakter tunggal), pertama-tama menentukan bahwa semua karakter memiliki bobot yang sama karena mereka semua " e ". Selanjutnya, itu menerapkan bobot aksen / diakritik. Tidak ada perbedaan casing sehingga langkah ketiga tidak akan mengubah apa pun. Jadi satu-satunya perbedaan adalah pada langkah 2, itulah sebabnya ada urutan pilihan untuk baris-baris tersebut col1.

Saat Anda mengurutkan berdasarkan col2(dua karakter), pertama-tama menentukan bahwa setiap baris memiliki bobot yang berbeda karena kedua karakter digunakan untuk menentukan bobot sortir (mis. " Ea ", " eb ", dll). Selanjutnya, itu menerapkan bobot aksen / diakritik. Tidak ada perbedaan casing sehingga langkah ketiga tidak akan mengubah apa pun. Jadi ada perbedaan dalam langkah 1 dan 2 kali ini. Tetapi karena perbedaan dalam langkah 1 telah diterapkan pada setiap string sebelum bobot langkah 2 dipertimbangkan, bobot dari langkah 2 tidak memiliki efek pada pemesanan; mereka hanya akan berlaku jika bobot dari langkah 1 untuk dua atau lebih baris adalah sama.

Adaptasi kode sampel berikut dari pertanyaan semoga menggambarkan perilaku penyortiran yang dijelaskan di atas. Saya menambahkan beberapa baris tambahan dan kolom tambahan untuk membantu menunjukkan dampak dari Collation menjadi case-sensitive (karena data sampel asli semuanya huruf kecil):

MEMPERSIAPKAN

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');

UJI 1

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

Pengembalian:

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

Apa yang bisa kita lihat dalam hasil di atas:

  1. Poin Kode tidak menentukan urutan pengurutan
  2. Karakter yang tidak beraksen diurutkan sebelum karakter yang beraksen (dalam huruf yang sama: f akan tetap datang setelah semua ini). Jelas, bobot aksen diterapkan sebelum bobot case.
  3. Jenis huruf kecil sebelum huruf besar dalam karakter aksen yang sama (atau non-aksen) (yaitu e lalu E , dan ë lalu Ë ). Penyesuaian ini digunakan oleh sebagian besar Windows Collations, sementara sebagian besar SQL Server Collations mengurutkan huruf besar terlebih dahulu.

UJI 2

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

Pengembalian:

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

Apa yang bisa kita lihat dalam hasil di atas:

  1. Penyortiran tingkat pertama benar-benar adalah karakter dasar. Jika itu aksen / diakritik maka baris ëC (id = 4), ēF (id = 10), dan EG (id = 5) tidak akan berada di tempatnya. Jika casing, maka baris EG (id = 5) tidak akan berada di tempatnya.
  2. Pemilahan tingkat kedua benar-benar adalah aksen / diakritik. Ini menjelaskan mengapa tiga baris terakhir adalah éH -> ëh -> ëH bukan ëh -> éH -> ëH (yaitu ID 3 -> 6 -> 9 bukannya 6 -> 3 -> 9).
  3. Pemilahan tingkat ketiga benar-benar adalah casing. Inilah sebabnya mengapa 2 baris terakhir adalah ' h ->' h , karena huruf kecil mengurutkannya terlebih dahulu.

UJI 3

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

Pengembalian:

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

Apa yang bisa kita lihat dalam hasil di atas:

  1. Urutan pengurutan persis sama dengan di Tes 2. Satu-satunya perbedaan dalam nilai tes di sini adalah bahwa ada ruang antara masing-masing karakter, menghilangkan kemungkinan aturan kontekstual. Oleh karena itu, kita tahu bahwa alasan perbedaan urutan untuk col2dalam pertanyaan lagi karena "Multi-Level Comparison", dan bukan "Sensitivitas Kontekstual".

Catatan tambahan:

  1. Berkenaan dengan mendapatkan aturan yang tepat, itu tidak semudah yang seharusnya. Masalah dengan mendapatkan penjelasan konkret dari aturan-aturan ini adalah bahwa aturan penyortiran Unicode, meskipun pasti didokumentasikan, adalah rekomendasi. Terserah vendor, seperti Microsoft, untuk mengimplementasikan rekomendasi tersebut. Microsoft tidak mengimplementasikan rekomendasi persis seperti yang dinyatakan dalam dokumentasi Unicode sehingga ada pemutusan di sana (mirip dengan bagaimana baik spesifikasi HTML atau CSS diimplementasikan sebagai sepenuhnya, atau bahkan dengan cara yang sama, di seluruh vendor). Lalu, ada versi berbeda dari Windows Collations (Anda menggunakan versi 100yang keluar dengan SQL Server 2008) dan yang terkait dengan versi Unicode yang jauh lebih tua dari versi Unicode saat ini atau demo ICU Collationsedang menggunakan. Misalnya, bagianApa yang Baru di SQL Server 2008 Collations bagian dari "Collation and Unicode Support" dokumentasi untuk SQL Server 2008 membuat 2 poin yang sangat menarik tentang apa yang "baru" untuk _100_seri Collations:

    1. Tabel kasus Unicode 5.0.

      Unicode 5.0 diterbitkan pada Juli 2006 (well, basis data karakter dirilis pada saat itu, dan spesifikasi lengkapnya menyusul pada akhir 2006). Versi saat ini adalah 10.0 yang diterbitkan pada Juni 2017. Dan mengingat pola rilis selama 4 tahun terakhir, kemungkinan versi 11.0 akan keluar sekitar pertengahan 2018.

    2. Bobot telah ditambahkan ke karakter yang sebelumnya tidak berbobot yang akan dibandingkan secara setara.

      Bobot-bobot itu lebih dari mungkin didefinisikan dalam Standar Unicode, hanya saja tidak dalam penerapannya.

     
    Namun, dokumentasi UCA yang ditautkan di atas adalah tempat yang baik untuk memulai.

  2. Sortir Kunci yang digunakan oleh Windows / .NET / SQL Server tidak persis sama dengan yang ditunjukkan dalam Standar Unicode (Lihat jawaban @ Patrick) atau diterapkan di ICU . Untuk melihat apa yang digunakan Windows / .NET / SQL Server, Anda dapat mencoba Metode CompareInfo.GetSortKey . Saya membuat SQLCLR UDF untuk memberikan nilai-nilai ini dan mendapatkan kunci sortir. Harap dicatat bahwa saya menggunakan SQL Server 2017 pada Windows 10 dengan .NET Framework 4.5 - 4.6.1 diinstal, jadi .NET harus menggunakan Unicode 6.0.0. Juga, Level4 tidak sedang digunakan untuk string ini.

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

    Melihat kunci pengurutan ini untuk Tes 1, dan menyadari bahwa level diurutkan seperti beberapa kolom dalam ORDER BYklausa (L3 diurutkan dalam nilai yang sama dengan L2, yang diurutkan dalam nilai yang sama dengan L1), harus menggambarkan bahwa alasan perilaku tercatat dalam pertanyaan sebenarnya adalah kemampuan penyortiran multi-level dari Unicode. Juga:

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

    Melihat beberapa kunci pengurutan untuk Uji 2, kita dapat melihat bahwa karakter dasar diurutkan terlebih dahulu (L1), kemudian aksen diurutkan (L2), dan kemudian casing diurutkan (L3).

  3. Karena datatype tersebut NVARCHAR, kami hanya memusatkan perhatian pada Unicode Code Points dan algoritma penyortiran, maka penggunaan UNICODE()fungsi dalam TEST 1. Sementara Code Code ditentukan oleh sebagian besar Collations, mereka hanya berkaitan dengan VARCHARdata. Berarti, sementara Kode 1252 ditentukan oleh Latin1_General*serangkaian Collations, yang dapat diabaikan di sini.

  4. Bobot yang dijelaskan dalam Tabel Elemen Unicode Kolom Default (DUCET) ( Versi 5.0.0 yang seharusnya memetakan ke _100_seri Koleksi) baik-baik saja untuk bahasa Inggris AS, tetapi tidak untuk lokal / bahasa lain. Bahasa lain harus dimulai dengan DUCET dan kemudian menerapkan aturan penggantian khusus lokal seperti yang ditentukan oleh proyek Common Locale Data Repository (CLDR). Dari apa yang saya tahu, versi 1.4 / 1.4.1 dirilis pada tahun 2006. Untuk mendapatkan penggantian tersebut, unduh file "inti" CLDR 1.4 melalui http://unicode.org/Public/cldr/1.4.0/core.zip , lalu, dalam file zip itu, buka folder collation dan temukan file XML yang sesuai dengan lokal yang digunakan. File-file itu hanya berisi penggantian, dan bukan set lengkap aturan pemeriksaan.

Solomon Rutzky
sumber