วิธี "ตัวละคร" หนึ่งตัว (ซึ่งอาจประกอบด้วยหลายจุดรหัส: คู่ตัวแทนการรวมตัวอักษรและอื่น ๆ ) เปรียบเทียบกับที่อื่นจะขึ้นอยู่กับชุดของกฎที่ค่อนข้างซับซ้อน มันซับซ้อนมากเนื่องจากจำเป็นต้องพิจารณากฎทั้งหมด (และบางครั้ง "แปลกประหลาด") ที่พบในทุกภาษาที่แสดงในข้อกำหนดUnicode ระบบนี้ใช้กับการจัดเรียงที่ไม่ใช่ไบนารีสำหรับNVARCHAR
ข้อมูลทั้งหมดและสำหรับVARCHAR
ข้อมูลที่ใช้การจัดเรียง Windows และไม่ใช่การจัดเรียงเซิร์ฟเวอร์ SQL (เริ่มต้นด้วยSQL_
) ระบบนี้ใช้ไม่ได้กับVARCHAR
ข้อมูลโดยใช้ SQL Server Collation เป็นระบบที่ใช้การแม็พอย่างง่าย
ส่วนใหญ่ของกฎที่มีการกำหนดไว้ในเปรียบเทียบ Unicode อัลกอริทึม (UCA) บางส่วนของกฎเหล่านั้นและบางส่วนไม่ได้กล่าวถึงใน UCA ได้แก่ :
- การสั่งซื้อ / น้ำหนักเริ่มต้นที่กำหนดใน
allkeys.txt
ไฟล์ (ระบุไว้ด้านล่าง)
- มีการใช้ความไวและตัวเลือกใด (เช่นเป็นตัวพิมพ์เล็กหรือตัวพิมพ์เล็กหรือไม่และถ้าละเอียดอ่อนแล้วตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็กก่อนหรือไม่)
- การแทนที่ตามโลแคลใด ๆ
- กำลังใช้เวอร์ชันของมาตรฐาน Unicode
- ปัจจัย "มนุษย์" (เช่น Unicode คือข้อกำหนดไม่ใช่ซอฟต์แวร์และถูกปล่อยให้ผู้ขายแต่ละรายทำการติดตั้ง)
ฉันย้ำว่าประเด็นสุดท้ายเกี่ยวกับปัจจัยมนุษย์เพื่อให้ชัดเจนว่าเราไม่ควรคาดหวังให้ SQL Server ทำงาน 100% ตามข้อกำหนดเสมอ
ปัจจัยที่เอาชนะได้ที่นี่คือการถ่วงน้ำหนักที่กำหนดให้กับแต่ละจุดของรหัสและความจริงที่ว่าจุดรหัสหลาย ๆ สามารถแบ่งปันข้อมูลจำเพาะน้ำหนักเดียวกัน คุณสามารถค้นหาตุ้มน้ำหนักพื้นฐาน (ไม่มีการแทนที่เฉพาะโลแคล) ที่นี่ (ฉันเชื่อว่า100
ชุด Collations คือ Unicode v 5.0 - การยืนยันอย่างไม่เป็นทางการในความคิดเห็นในรายการMicrosoft Connect ):
http://www.unicode.org/Public/UCA/5.0.0/allkeys.txt
จุดรหัสที่เป็นปัญหา - U + FFFD - ถูกกำหนดเป็น:
FFFD ; [*0F12.0020.0002.FFFD] # REPLACEMENT CHARACTER
สัญกรณ์ดังกล่าวถูกกำหนดไว้ในส่วนที่9.1 รูปแบบไฟล์ Allkeysของ UCA:
<entry> := <charList> ';' <collElement>+ <eol>
<charList> := <char>+
<collElement> := "[" <alt> <weight> "." <weight> "." <weight> ("." <weight>)? "]"
<alt> := "*" | "."
Collation elements marked with a "*" are variable.
บรรทัดสุดท้ายนั้นมีความสำคัญเนื่องจากจุดรหัสที่เรากำลังดูมีข้อมูลจำเพาะที่ขึ้นต้นด้วย "*" ในส่วนที่3.6 น้ำหนักที่เปลี่ยนแปลงได้มีการกำหนดพฤติกรรมที่เป็นไปได้สี่ประการโดยขึ้นอยู่กับค่าการกำหนดค่าการจัดเรียงที่เราไม่สามารถเข้าถึงได้โดยตรง ตัวพิมพ์ใหญ่ก่อนคุณสมบัติที่แตกต่างระหว่างVARCHAR
ข้อมูลโดยใช้SQL_
Collations และรูปแบบอื่น ๆ ทั้งหมด)
ฉันไม่มีเวลาที่จะทำการวิจัยอย่างเต็มรูปแบบเกี่ยวกับเส้นทางที่ถูกนำมาใช้และอนุมานว่ามีตัวเลือกใดบ้างที่ถูกใช้เพื่อให้มีการพิสูจน์ที่มั่นคงมากขึ้น แต่มันก็ปลอดภัยที่จะพูดว่า ถือว่า "เท่ากัน" จะไม่ใช้ข้อมูลจำเพาะแบบเต็มเสมอไป ในกรณีนี้เรามี "0F12.0020.0002.FFFD" และส่วนใหญ่เป็นเพียงระดับ 2 และ 3 ที่ใช้งานอยู่ (เช่น. 0020.0002 ) ทำ "นับ" ใน Notepad ++ สำหรับ ".0020.0002" พบการแข่งขัน 12,581 ครั้ง (รวมถึงตัวละครเสริมที่เรายังไม่ได้ติดต่อด้วย) การทำ "Count" กับ "[*" จะคืนค่า 4049 ที่ตรงกัน ทำ RegEx "Find" / "Count" โดยใช้รูปแบบของ\[\*\d{4}\.0020\.0002
ส่งคืนการแข่งขัน 832 รายการ ดังนั้นในชุดค่าผสมนี้รวมถึงกฎบางอย่างที่ฉันไม่เห็นอีกทั้งรายละเอียดการใช้งานเฉพาะของ Microsoft คือคำอธิบายแบบเต็มของพฤติกรรมนี้ และเพื่อให้ชัดเจนพฤติกรรมจะเหมือนกันสำหรับอักขระที่ตรงกันทั้งหมดเนื่องจากทั้งหมดมีน้ำหนักเท่ากันเมื่อกฎถูกนำไปใช้ (ความหมายคำถามนี้อาจถูกถามเกี่ยวกับคำถามใดคำถามหนึ่งของพวกเขาไม่ใช่ นายจำเป็นต้อง�
)
คุณสามารถดูด้วยแบบสอบถามด้านล่างและเปลี่ยนCOLLATE
ประโยคตามผลลัพธ์ด้านล่างแบบสอบถามว่าความไวต่างๆทำงานได้อย่างไรใน Collations ทั้งสองรุ่น:
;WITH cte AS
(
SELECT TOP (65536) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1 AS [Num]
FROM [master].sys.columns col
CROSS JOIN [master].sys.objects obj
)
SELECT cte.Num AS [Decimal],
CONVERT(VARBINARY(2), cte.Num) AS [Hex],
NCHAR(cte.Num) AS [Character]
FROM cte
WHERE NCHAR(cte.Num) = NCHAR(0xFFFD) COLLATE Latin1_General_100_CS_AS_WS --N'�'
ORDER BY cte.Num;
จำนวนอักขระที่ตรงกันในการเปรียบเทียบที่แตกต่างกันอยู่ด้านล่าง
Latin1_General_100_CS_AS_WS = 5840
Latin1_General_100_CS_AS = 5841 (The "extra" character is U+3000)
Latin1_General_100_CI_AS = 5841
Latin1_General_100_CI_AI = 6311
Latin1_General_CS_AS_WS = 21,229
Latin1_General_CS_AS = 21,230
Latin1_General_CI_AS = 21,230
Latin1_General_CI_AI = 21,537
ในการเปรียบเทียบทั้งหมดที่ระบุไว้ข้างต้นN'' = N'�'
จะประเมินเป็นจริง
UPDATE
ฉันสามารถทำการวิจัยเพิ่มเติมอีกเล็กน้อยและนี่คือสิ่งที่ฉันพบ:
มันควรจะทำงานอย่างไร
ใช้ICU Collation Demoฉันตั้งค่าภาษาเป็น "en-US-u-va-posix" ตั้งค่าความแข็งแกร่งเป็น "หลัก" ตรวจสอบการแสดง "คีย์เรียง" และแสดงใน 4 ตัวอักษรต่อไปนี้ที่ฉันคัดลอกมาจาก ผลลัพธ์ของข้อความค้นหาด้านบน (ใช้Latin1_General_100_CI_AI
Collation):
�
Ԩ
ԩ
Ԫ
และผลตอบแทนที่ได้:
Ԫ
60 2E 02 .
Ԩ
60 7A .
ԩ
60 7A .
�
FF FD .
จากนั้นตรวจสอบคุณสมบัติของอักขระสำหรับ " " ที่http://unicode.org/cldr/utility/character.jsp?a=fffdและดูว่าคีย์การเรียงระดับ 1 (เช่นFF FD
) ตรงกับคุณสมบัติ "uca" การคลิกที่คุณสมบัติ "uca" จะนำคุณไปยังหน้าการค้นหา - http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3Auca%3DFFFD%3A%5D - แสดงการแข่งขันเพียง 1 รายการ และในไฟล์allkeys.txtน้ำหนักการจัดเรียงระดับ 1 จะแสดงเป็น0F12
และมีเพียง 1 รายการที่ตรงกัน
เพื่อให้แน่ใจว่าเรากำลังตีความพฤติกรรมอย่างถูกต้องฉันดูตัวละครอื่น: GREEK Capital LETTER OMICRON กับ VARIA Ὸ
ที่http://unicode.org/cldr/utility/character.jsp?a=1FF8ซึ่งมี "uca" ( คือระดับน้ำหนัก 1 เรียงลำดับ / องค์ประกอบเรียง) 5F30
ของ คลิกที่ "5F30" พาเราไปที่หน้าค้นหา - http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3Auca%3D5F30%3A%5D - แสดง 30 แมตช์, 20 จาก พวกเขาอยู่ในช่วง 0 - 65535 (เช่น U + 0000 - U + FFFF) มองในallkeys.txtไฟล์สำหรับรหัสจุด1FF8เราจะเห็นมีน้ำหนักจัดเรียงระดับ 12E0
1 ทำ "นับ" ใน Notepad ++ เปิด12E0.
แสดงการจับคู่ 30 รายการ (ตรงกับผลลัพธ์ที่ได้จาก Unicode.org แม้ว่าจะไม่รับประกันว่าจะเป็นเพราะไฟล์สำหรับ Unicode v 5.0 และไซต์กำลังใช้ข้อมูล Unicode v 9.0)
ใน SQL Server เคียวรีต่อไปนี้ส่งคืนการจับคู่ 20 รายการเหมือนกับการค้นหา Unicode.org เมื่อลบอักขระเสริม 10 ตัว:
;WITH cte AS
(
SELECT TOP (65535) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [Num]
FROM [master].sys.columns col
CROSS JOIN [master].sys.objects obj
)
SELECT cte.Num AS [Decimal],
CONVERT(VARCHAR(50), CONVERT(VARBINARY(2), cte.Num), 2) AS [Hex],
NCHAR(cte.Num) AS [Character]
FROM cte
WHERE NCHAR(cte.Num) = NCHAR(0x1FF8) COLLATE Latin1_General_100_CI_AI
ORDER BY cte.Num;
และเพื่อให้แน่ใจว่าจะกลับไปที่หน้า ICU Collation Demo และแทนที่อักขระในกล่อง "Input" ด้วยอักขระ 3 ตัวต่อไปนี้ที่นำมาจากรายการผลลัพธ์ 20 รายการจาก SQL Server:
Ὂ
𝜪
Ὸ
แสดงให้เห็นว่าพวกเขาทั้งหมดมี5F 30
น้ำหนักเรียงลำดับ 1 ระดับเดียวกัน(ตรงกับฟิลด์ "uca" บนหน้าคุณสมบัติอักขระ)
ดังนั้นมันจึงดูเหมือนกับว่าตัวละครตัวนี้ไม่ควรตรงกับสิ่งอื่นใด
มันใช้งานได้จริง (อย่างน้อยใน Microsoft-land)
ซึ่งแตกต่างจากภายใน SQL Server, .NET มีวิธีการแสดงที่สำคัญการจัดเรียงสตริงผ่านเป็นวิธี CompareInfo.GetSortKey ใช้วิธีนี้และผ่านในเวลาเพียงตัวอักษร U + FFFD 0x0101010100
ก็จะส่งกลับคีย์การเรียงลำดับของ จากนั้นวนซ้ำอักขระทั้งหมดในช่วง 0 - 65535 เพื่อดูว่าอักขระใดมีคีย์การเรียงลำดับของการ0x0101010100
แข่งขันที่ส่งคืน 4529 สิ่งนี้ไม่ตรงกับ 5840 ที่ส่งคืนใน SQL Server (เมื่อใช้Latin1_General_100_CS_AS_WS
Collation) แต่มันใกล้เคียงที่สุดที่เราจะได้รับ (ตอนนี้) เนื่องจากฉันใช้ Windows 10 และ. NET Framework รุ่น 4.6.1 ซึ่งใช้ Unicode v 6.3.0 ตามแผนภูมิสำหรับCharUnicodeInfo Class(ใน "บันทึกถึงผู้โทร" ในส่วน "หมายเหตุ") ในขณะที่ฉันกำลังใช้ฟังก์ชั่น SQLCLR และดังนั้นจึงไม่สามารถเปลี่ยนรุ่น Framework ของเป้าหมายได้ เมื่อฉันมีโอกาสฉันจะสร้างแอปคอนโซลและใช้ Framework Framework รุ่น 4.5 ตามเป้าหมายที่ใช้ Unicode v 5.0 ซึ่งควรตรงกับ 100 Series Collations
สิ่งที่การทดสอบนี้แสดงให้เห็นคือแม้ว่าจะไม่มีการจับคู่ที่ตรงกันระหว่าง. NET และ SQL Server สำหรับ U + FFFD เป็นจำนวนเท่ากันมันก็ค่อนข้างชัดเจนว่านี่ไม่ใช่การทำงานเฉพาะของ SQL Server และไม่ว่าจะเป็นการจงใจหรือการกำกับดูแล โดย Microsoft ตัวละคร U + FFFD นั้นจะจับคู่กับตัวละครได้ไม่กี่ตัวแม้ว่ามันจะไม่เป็นไปตามข้อกำหนดของ Unicode ก็ตาม และเนื่องจากอักขระนี้ตรงกับ U + 0000 (null) อาจเป็นเพียงปัญหาของน้ำหนักที่หายไป
นอกจากนี้
เกี่ยวกับความแตกต่างของพฤติกรรมในการ=
สืบค้นเทียบกับการLIKE N'%�%'
สืบค้นนั้นเกี่ยวข้องกับอักขระตัวแทนและน้ำหนักที่หายไป (ฉันถือว่า) สำหรับ� Ƕ Ƿ Ǹ
อักขระ(เช่น) เหล่านี้ หากLIKE
เงื่อนไขถูกเปลี่ยนให้เป็นเพียงแค่LIKE N'�'
มันจะส่งคืน 3 แถวเดียวกันกับ=
เงื่อนไข หากปัญหาเกี่ยวกับไวลด์การ์ดนั้นไม่ได้เกิดจากน้ำหนัก "หายไป" (ไม่มี0x00
คีย์การส่งคืนโดยCompareInfo.GetSortKey
btw) อาจเป็นเพราะอักขระเหล่านี้อาจมีคุณสมบัติที่อนุญาตให้คีย์เรียงลำดับแตกต่างกันตามบริบท (เช่นอักขระโดยรอบ )
FFFD
(การค้นหา*0F12.0020.0002.FFFD
เพียงส่งกลับผลลัพธ์เดียว) จากการสังเกตของ @ Forrest ว่าพวกเขาทั้งหมดตรงกับสตริงว่างและอ่านอีกเล็กน้อยเกี่ยวกับเรื่องดูเหมือนว่าน้ำหนักที่พวกเขามีส่วนร่วมในการเปรียบเทียบไม่ใช่ไบนารีที่แตกต่างกันในความเป็นจริงฉันเชื่อว่าเป็นศูนย์