Sắp xếp nhạy cảm


19

Tại sao hai SELECTcâu lệnh này dẫn đến một thứ tự sắp xếp khác nhau?

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 ║ - nên là 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
╚════╩══════╩══════╝

Câu trả lời:


13

Câu hỏi này không liên quan đến cơ sở dữ liệu mà nhiều hơn về quy tắc và xử lý Unicode.

Dựa trên https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql Latin1_General_100_CS_AS có nghĩa là: "Collation sử dụng quy tắc sắp xếp từ điển chung của Latin1 và bản đồ 1252 "có thêm CS = Case Sensitive và AS = Accent Sensitive.

Ánh xạ giữa trang mã Windows 1252 và Unicode ( http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT ) hiển thị cùng các giá trị cho tất cả các ký tự chúng ta đang xử lý (ngoại trừ e với macron điều đó không tồn tại trong bản đồ của Microsoft, vì vậy không biết nó làm gì với trường hợp này), vì vậy chúng ta có thể tập trung vào các công cụ và thuật ngữ Unicode ngay bây giờ.

Trước tiên, hãy cho chúng tôi biết chính xác những gì chúng tôi đang xử lý, cho tất cả các chuỗi của bạn:

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

Thuật toán đối chiếu Unicode được mô tả tại đây: https://www.unicode.org/reports/tr10/

Hãy xem phần 1.3 "Độ nhạy theo ngữ cảnh" giải thích rằng việc sắp xếp không thể phụ thuộc vào chỉ một ký tự sau khi một số quy tắc nhạy cảm theo ngữ cảnh.

Cũng lưu ý những điểm này trong 1.8:

Đối chiếu không phải là một thuộc tính của chuỗi. Thứ tự đối chiếu không được bảo toàn trong các hoạt động nối hoặc chuỗi con, nói chung.

Theo mặc định, thuật toán sử dụng ba cấp độ tùy biến hoàn toàn. Đối với tập lệnh Latin, các mức này tương ứng với:

alphabetic ordering
diacritic ordering
case ordering.

Nhưng thuật toán tự nó là một chút dày đặc. Ý chính của nó là: Nói ngắn gọn, Thuật toán đối chiếu Unicode lấy một chuỗi Unicode đầu vào và Bảng thành phần đối chiếu, chứa dữ liệu ánh xạ cho các ký tự. Nó tạo ra một khóa sắp xếp, là một mảng các số nguyên 16 bit không dấu. Hai hoặc nhiều khóa sắp xếp được tạo ra sau đó có thể được so sánh nhị phân để so sánh chính xác giữa các chuỗi mà chúng được tạo.

Bạn có thể xem các quy tắc sắp xếp tiếng Latin cụ thể tại đây: http://developer.mimer.com/collations/charts/latin.htm hoặc trực tiếp hơn và cụ thể hơn cho MS SQL: http://collation-charts.org/mssql/mssql. 0409.1252.Latin1_General_CS_AS.html

Đối với enhân vật nó thể hiện:

e é É è È ê Ê ë

Điều này giải thích kết quả của bạn khi đặt hàng col1ngoại trừ ē không tồn tại trong trang mã 1252, vì vậy tôi hoàn toàn không biết nó làm gì với nó.

Hoặc nếu chúng tôi thực hiện thuật toán Unicode bằng tay, sử dụng giá trị khóa của DUCET tại http://www.unicode.org/Public/UCA/latest/allkeys.txt :

Bước 1: Chuẩn hóa mẫu D, vì vậy mỗi trường hợp trở thành:

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

Bước 2, Tạo mảng đối chiếu (tra cứu trong tệp 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]

Bước 3, Tạo các khóa sắp xếp (cho mỗi cấp độ, lấy từng giá trị bên trong mỗi mảng đối chiếu, sau đó đặt 0000 làm dấu phân cách và bắt đầu lại cho cấp độ tiếp theo)

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

Bước 4, So sánh các khóa sắp xếp (so sánh nhị phân đơn giản của từng giá trị một): Giá trị thứ tư là đủ để sắp xếp tất cả chúng, vì vậy thứ tự cuối cùng trở thành:

e
é
è
ê
ë
ē

Theo cách tương tự để đặt hàng trên col2:

bước 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

Bước 2: Mảng đối chiếu

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]

Bước 3: Tạo các phím sắp xếp

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

Bước 4: So sánh các khóa sắp xếp: Giá trị thứ hai là đủ để sắp xếp tất cả chúng, và thực tế nó đã theo thứ tự tăng dần, vì vậy thứ tự cuối cùng thực sự là:

eA
éB
ëC
èD
êE
ēF

Cập nhật : thêm trường hợp thứ ba của Solomon Rutzky, khó khăn hơn vì không gian cho phép các quy tắc mới (tôi đã chọn "trường hợp không thể bỏ qua"):

bước 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

Bước 2, Tạo mảng đối chiếu:

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

Bước 3, Phím sắp xếp biểu mẫu:

è 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

Bước 4, So sánh các phím sắp xếp:

Về cơ bản giá trị thứ ba xác định thứ tự và trên thực tế nó chỉ dựa trên chữ số cuối cùng, vì vậy thứ tự phải là:

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

Cập nhật thứ hai dựa trên nhận xét của Solomon Rutzky về các phiên bản Unicode.

Tôi đã sử dụng allkeys.txtdữ liệu về phiên bản Unicode mới nhất tại thời điểm này, đó là phiên bản 10.0

Thay vào đó, nếu chúng ta cần đưa vào tài khoản Unicode 5.1 , đây sẽ là: http://www.unicode.org/Public/UCA/5.1.0/allkeys.txt

Tôi chỉ kiểm tra, đối với tất cả các ký tự ở trên, các mảng đối chiếu là như sau:

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]

và:

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]

và:

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

mà sau đó tính toán với các phím sắp xếp sau:

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

và:

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

và:

è 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

một lần nữa cho ba kết quả được sắp xếp sau:

e
é
è
ê
ë
ē

eA
éB
ëC
èD
êE
ēF

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

Xin chào Patrick. Cảm ơn đã đăng thông tin chi tiết này. Một vài lưu ý: 1) Bạn có thể bỏ qua Mã Trang 1252. Đó là đối với VARCHARdữ liệu (không phải là Unicode), không được sử dụng ở đây. Đó là lý do tại sao ēnhân vật hoạt động tốt. 2) Thông tin "biểu đồ đối chiếu" hơi lỗi thời. Đây là phiên bản trước của Collation này và họ chưa đăng bất cứ thứ gì kể từ năm 2009. 3) Phiên bản Unicode ở đây chắc chắn không phải là phiên bản mới nhất (Phiên bản 10). Các _100_loạt Collations đi kèm với SQL 2008, vì vậy đây sẽ là Unicode 5.0 hoặc 5.1: unicode.org/standard/versions/#TUS_Earlier_Versions
Solomon Rutzky

Tôi không nghĩ những allKeys.txt thay đổi giữa phiên bản Unicode, bên cạnh việc bổ sung các ký tự mới, vì vậy những điều trên vẫn đúng nhưng tất nhiên nó có thể được làm lại với dữ liệu cũ trước đó, tôi chỉ thiếu năng lượng để đặt lại vài giờ vào đó. Đối với CP1252, nó chỉ xuất phát từ định nghĩa do MS-SQL đưa ra (bản thân tôi không sử dụng sản phẩm này).
Patrick Mevzek

1) Có thể không có thay đổi lớn giữa các phiên bản, nhưng tôi khá chắc chắn rằng ít nhất có sự điều chỉnh trọng lượng / phân loại. Nhưng vâng, tôi chắc chắn nhận được các hạn chế về thời gian;) 2) Về CP1252, tôi đã đề cập đến nó vì khái niệm Trang mã không tồn tại trong Unicode. Unicode là một phương tiện không bao giờ cần các trang mã. Tài liệu MS được thừa nhận không rõ ràng về điều này, nhưng nó đề cập đến phía trên " Trang mã được sử dụng để lưu trữ dữ liệu ký tự không phải là Unicode. " Bạn đúng là một ký tự không có trong CP1252, nhưng Trang mã không xuất hiện ở đây.
Solomon Rutzky

Có, tôi chưa bao giờ nói bất cứ điều gì về trang mã liên quan đến Unicode. Đây chỉ là tài liệu MS SQL nói rằng tên đối chiếu này hoạt động với "trang mã 1252". Nó có thể không có ý nghĩa (Nó không đối với tôi, nhưng một lần nữa, không phải là người dùng của nó) nhưng đó là những gì được viết trong tài liệu của phần mềm này. Đối với việc làm lại công việc, vui lòng thực hiện hoặc chỉ cung cấp các thay đổi về cách sắp xếp liên quan đến các nhân vật đang chơi ở đây kết hợp với Unicode 5 và mới nhất, nếu có và nếu bạn muốn. Tôi tin rằng câu trả lời của tôi là chính xác, là chính xác và xây dựng kết quả dựa trên đầu vào, không phải theo cách khác.
Patrick Mevzek

3) re: câu # 1: trong khi chủ yếu là về Unicode, câu hỏi này là vấn đề về hệ điều hành do MS triển khai thông số kỹ thuật và có thể đã không thực hiện tất cả và / hoặc có thể đã mắc một số lỗi. Tôi đã tìm thấy 2 lỗi trong .NET liên quan đến cách xác định "danh mục" hoặc "khối" mà một nhân vật cụ thể đang ở (họ đã xác định nhầm một phân đoạn nhỏ của các ký tự). Ngoài ra, đây , ít nhất là một chút, một vấn đề SQL Server, chỉ vì SQL Server có hiệu quả một bản chụp của từng Collation tại một điểm trong thời gian (đối với tính nhất quán giữa các phiên bản), để họ có thể có những gì tại là SQL hành vi máy chủ cụ thể.
Solomon Rutzky

16

Nói chung, hành vi mà bạn đang thấy ở đây là do thực tế là Thuật toán đối chiếu Unicode (UCA) cho phép sắp xếp phức tạp, đa cấp. Cụ thể hơn:

  1. Sắp xếp không so sánh:

    Việc xác định xem hai chuỗi giống nhau hay khác nhau là khá đơn giản (đưa ra một ngôn ngữ / ngôn ngữ cụ thể và tập hợp độ nhạy). Nhưng việc xác định thứ tự từ 2 chuỗi trở lên có thể rất phức tạp.

  2. Sắp xếp được thực hiện trong một loạt các bước, với mỗi bước được áp dụng cho toàn bộ chuỗi, không phải theo từng ký tự:

    1. Tiêu chuẩn: sắp xếp các ký tự cơ sở (không phân biệt dấu trọng âm và trường hợp)
    2. NẾU nhạy cảm với trọng âm, áp dụng trọng số trọng âm / dấu phụ
    3. NẾU phân biệt chữ hoa chữ thường, áp dụng trọng lượng vỏ

Khi bạn sắp xếp theo col1(ký tự đơn), trước tiên, nó sẽ xác định rằng tất cả các ký tự có cùng trọng số vì chúng đều là " e ". Tiếp theo, nó áp dụng trọng số trọng âm / dấu phụ. Không có sự khác biệt về vỏ nên bước thứ ba sẽ không thay đổi gì cả. Vì vậy, sự khác biệt duy nhất là ở bước 2, đó là lý do tại sao có một thứ tự ưu tiên cho các hàng dựa trêncol1 .

Khi bạn sắp xếp theo col2(hai ký tự), trước tiên, nó sẽ xác định rằng mỗi hàng có trọng số khác nhau vì cả hai ký tự được sử dụng để xác định trọng lượng sắp xếp (ví dụ: " ea ", " eb ", v.v.). Tiếp theo, nó áp dụng trọng số trọng âm / dấu phụ. Không có sự khác biệt về vỏ nên bước thứ ba sẽ không thay đổi gì cả. Vì vậy, có sự khác biệt trong bước 1 và 2 lần này. Nhưng vì sự khác biệt trong bước 1 đã được áp dụng cho từng chuỗi trước khi các trọng số của bước 2 được xem xét, các trọng số từ bước 2 không có bất kỳ ảnh hưởng nào đến việc đặt hàng; chúng sẽ chỉ áp dụng nếu các trọng số từ bước 1 cho hai hoặc nhiều hàng giống nhau.

Sự thích ứng sau đây của mã mẫu từ câu hỏi hy vọng minh họa hành vi sắp xếp được mô tả ở trên. Tôi đã thêm một số hàng bổ sung và một cột bổ sung để giúp hiển thị tác động của Collation có phân biệt chữ hoa chữ thường (vì dữ liệu mẫu ban đầu đều là chữ thường):

THIẾT LẬP

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

KIỂM TRA 1

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

Trả về:

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

Những gì chúng ta có thể thấy trong các kết quả trên:

  1. Điểm mã không xác định thứ tự sắp xếp
  2. Các ký tự không có dấu được sắp xếp trước các ký tự có dấu (trong cùng một chữ cái: f vẫn sẽ đến sau tất cả các ký tự này). Rõ ràng, trọng lượng trọng âm được áp dụng trước trọng lượng trường hợp.
  3. Thấp hơn hợp cụ thể loại trước khi chữ hoa trong nhân vật có dấu (hoặc không có dấu) cùng (tức là e rồi E , và ë sau đó Ë ). Điều chỉnh này được sử dụng bởi hầu hết các Bộ sưu tập Windows, trong khi hầu hết các Bộ sưu tập SQL Server sắp xếp chữ hoa trước.

KIỂM TRA 2

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

Trả về:

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

Những gì chúng ta có thể thấy trong các kết quả trên:

  1. Sắp xếp cấp đầu tiên thực sự là các nhân vật cơ sở. Nếu đó là dấu / dấu phụ thì các hàng ëC (id = 4), ēF (id = 10) và EG (id = 5) sẽ không ở vị trí của chúng. Nếu nó là vỏ, thì hàng EG (id = 5) sẽ không ở đâu.
  2. Sắp xếp cấp hai thực sự là các dấu / dấu phụ. Điều này giải thích tại sao ba hàng cuối cùng là éH -> ëh -> ëH thay vì ëh -> éH -> ëH (tức là ID 3 -> 6 -> 9 thay vì 6 -> 3 -> 9).
  3. Phân loại cấp ba thực sự là vỏ. Đây là lý do tại sao 2 hàng cuối cùng là ëh -> ëH , vì các chữ thường được sắp xếp trước.

KIỂM TRA 3

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

Trả về:

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

Những gì chúng ta có thể thấy trong các kết quả trên:

  1. Thứ tự sắp xếp hoàn toàn giống như trong Thử nghiệm 2. Sự khác biệt duy nhất trong các giá trị thử nghiệm ở đây là có một khoảng cách giữa mỗi ký tự, loại bỏ khả năng của các quy tắc theo ngữ cảnh. Do đó, chúng tôi biết rằng lý do cho sự khác biệt về thứ tự sắp xếp col2trong câu hỏi một lần nữa là do "So sánh đa cấp" chứ không phải "Nhạy cảm theo ngữ cảnh".

Ghi chú bổ sung:

  1. Liên quan đến việc có được các quy tắc chính xác, điều đó không dễ dàng như nó phải được. Vấn đề với việc giải thích cụ thể các quy tắc này là các quy tắc sắp xếp Unicode, trong khi chắc chắn được ghi lại, là một khuyến nghị. Tùy thuộc vào các nhà cung cấp, như Microsoft, để thực hiện các khuyến nghị đó. Microsoft đã không triển khai các khuyến nghị chính xác như được nêu trong tài liệu Unicode nên có một sự ngắt kết nối ở đó (tương tự như cách các thông số kỹ thuật HTML hoặc CSS không được triển khai hoàn toàn, thậm chí theo cùng một cách, giữa các nhà cung cấp). Sau đó, có các phiên bản khác nhau của Windows Collations (bạn đang sử dụng phiên bản 100đi kèm với SQL Server 2008) và được gắn với phiên bản Unicode cũ hơn nhiều so với phiên bản Unicode hiện tại hoặc của bản demo Collation ICU đang sử dụng. Ví dụ:Phần mới của SQL Server 2008 Collations trong tài liệu "Collation và Unicode Support" cho SQL Server 2008 tạo ra 2 điểm rất thú vị về những gì "mới" trong _100_loạt Collations:

    1. Bảng trường hợp Unicode 5.0.

      Unicode 5.0 đã được xuất bản vào tháng 7 năm 2006 (tốt, cơ sở dữ liệu ký tự được phát hành sau đó, và thông số đầy đủ theo sau vào cuối năm 2006). Phiên bản hiện tại là 10.0 được xuất bản vào tháng 6 năm 2017. Và với mô hình phát hành trong 4 năm qua, có khả năng phiên bản 11.0 sẽ ra mắt vào giữa năm 2018.

    2. Trọng số đã được thêm vào các ký tự không có trọng số trước đây sẽ được so sánh như nhau.

      Các trọng số đó nhiều khả năng được xác định trong Tiêu chuẩn Unicode, chỉ là không triển khai nó.

     
    Tuy nhiên, tài liệu UCA được liên kết ở trên là một nơi tốt để bắt đầu.

  2. Các khóa sắp xếp được sử dụng bởi Windows / .NET / SQL Server không hoàn toàn giống như được hiển thị trong Tiêu chuẩn Unicode (Xem câu trả lời của @ Patrick) hoặc được triển khai trong ICU . Để xem Windows / .NET / SQL Server sử dụng cái gì, bạn có thể thử Phương thức so sánhInIn.GetSortKey . Tôi đã tạo một UDF SQLCLR để truyền vào các giá trị này và nhận khóa sắp xếp. Xin lưu ý rằng tôi đang sử dụng SQL Server 2017 trên Windows 10 với .NET Framework 4.5 - 4.6.1 được cài đặt, vì vậy .NET nên sử dụng Unicode 6.0.0. Ngoài ra, Level4 không được sử dụng cho các chuỗi này.

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

    Nhìn vào các khóa sắp xếp này cho Bài kiểm tra 1 và nhận ra rằng các mức được sắp xếp giống như nhiều cột trong một ORDER BYmệnh đề (L3 được sắp xếp trong cùng các giá trị của L2, được sắp xếp trong cùng các giá trị của L1), nên minh họa rằng lý do cho hành vi Trên thực tế, lưu ý trong câu hỏi là khả năng sắp xếp đa cấp của Unicode. Tương tự như vậy:

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

    Nhìn vào một số phím sắp xếp cho Bài kiểm tra 2, chúng ta có thể thấy các ký tự cơ sở được sắp xếp trước (L1), sau đó các dấu được sắp xếp (L2), và sau đó vỏ được sắp xếp (L3).

  3. Vì kiểu dữ liệu là NVARCHAR, chúng tôi chỉ quan tâm đến các Điểm Mã và thuật toán sắp xếp Unicode, do đó việc sử dụng UNICODE()hàm trong KIỂM TRA 1. Trong khi các Trang Mã được chỉ định bởi hầu hết các Collations, chúng chỉ liên quan đến VARCHARdữ liệu. Có nghĩa là, trong khi Bộ luật Trang 1252 được chỉ định bởi Latin1_General*loạt Collations, có thể bỏ qua ở đây.

  4. Các trọng số được mô tả trong Bảng thành phần đối chiếu Unicode mặc định (DUCET) ( Phiên bản 5.0.0 sẽ ánh xạ tới _100_chuỗi Collations) phù hợp với tiếng Anh Mỹ, nhưng không phải là ngôn ngữ / ngôn ngữ khác. Các ngôn ngữ khác cần bắt đầu với DUCET và sau đó áp dụng các quy tắc ghi đè dành riêng cho miền địa phương như được xác định bởi dự án Kho lưu trữ dữ liệu địa phương chung (CLDR). Từ những gì tôi có thể nói, các phiên bản 1.4 / 1.4.1 đã được phát hành vào năm 2006. Để có được các phần ghi đè đó, hãy tải xuống tệp "lõi" CLDR 1.4 qua http://unicode.org/Public/cldr/1.4.0/core.zip , sau đó, trong tệp zip đó, đi đến thư mục đối chiếu và tìm tệp XML tương ứng với ngôn ngữ được sử dụng. Các tệp đó chỉ chứa các phần ghi đè và không phải là bộ quy tắc đối chiếu hoàn chỉnh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.