การเข้ารหัส UCS-2 มีค่า 2 ไบต์ต่อตัวอักษรและมีช่วงตั้งแต่ 0 - 65535 (0x0000 - 0xFFFF) UTF-16 (โดยไม่คำนึงถึง Big Endian หรือ Little Endian) มีช่วง 0 - 1114111 (0x0000 - 0x10FFFF) ช่วง 0 - 65535 / 0x0000 - 0xFFFF ของ UTF-16 คือ 2 ไบต์ต่อตัวอักษรในขณะที่ช่วงเหนือ 65536 / 0xFFFF คือ 4 ไบต์ต่อตัวอักษร
Windows และ SQL Server เริ่มต้นด้วยการเข้ารหัส UCS-2 เพราะใช้งานได้และ UTF-16 ยังไม่สิ้นสุด อย่างไรก็ตามโชคดีที่มีการคิดล่วงหน้าเพียงพอในการออกแบบ UCS-2 และ UTF-16 ที่การแมป UCS-2 เป็นชุดย่อยที่สมบูรณ์ของการแมป UTF-16 (ความหมาย: ช่วง 0 - 65535 / 0x0000 - 0xFFFF ของ UTF-16 คือ UCS-2) และช่วง 65536 - 1114111 (0x10000 - 0x10FFFF) ของ UTF-16 นั้นสร้างขึ้นจากจุดรหัสสองจุดในช่วง UCS-2 (ช่วง 0xD800 - 0xDBFF และ 0xDC00 - 0xDFFF โดยเฉพาะ) ซึ่งถูกสงวนไว้สำหรับจุดประสงค์นี้และไม่มี ความหมาย การรวมกันของสองรหัสคะแนนนี้เรียกว่าคู่ตัวแทนและคู่ตัวแทนแทนตัวละครเกินช่วง UCS-2 ซึ่งเป็นที่รู้จักกันเป็นตัวละครเสริม
ข้อมูลทั้งหมดนั้นอธิบายสองด้านของNVARCHAR
ข้อมูล / Unicode ใน SQL Server:
- หลายฟังก์ชั่น (ไม่เพียง แต่
NCHAR()
) ไม่จัดการคู่ตัวแทน / ตัวละครเสริมเมื่อไม่ได้ใช้เสริม Character-Aware เปรียบเทียบ (SCA นั่นคือหนึ่งเดียวกับ_SC
, หรือ _140_
แต่ไม่_BIN*
ในชื่อ) เพราะไม่ใช่ SCA Collations (โดยเฉพาะอย่างยิ่งSQL_
การจัดเรียง) ถูกนำมาใช้ก่อนที่ UTF-16 จะแล้วเสร็จ (บางครั้งในปี 2000 ฉันเชื่อ) ไม่ใช่การSQL_
เรียงที่มี_90_
หรือ_100_
ในชื่อของพวกเขา แต่ไม่_SC
ได้รับการสนับสนุนขั้นต่ำสำหรับอักขระเสริมในแง่ของการเปรียบเทียบและการเรียงลำดับ
- ชุดอักขระ Unicode / UTF-16 แบบเต็มสามารถจัดเก็บได้โดยไม่สูญเสียข้อมูลใด ๆ ใน
NVARCHAR
/ NCHAR
/ XML
/ NTEXT
datatypes เนื่องจาก UCS-2 และ UTF-16 เป็นลำดับไบต์ที่แน่นอนเดียวกัน ข้อแตกต่างเพียงอย่างเดียวคือ UTF-16 ใช้ประโยชน์จากจุดรหัสตัวแทนเพื่อสร้าง Surrogate Pairs และ UCS-2 ไม่สามารถแมปกับอักขระใด ๆ ได้ดังนั้นจึงปรากฏเป็นฟังก์ชันในตัวเป็นอักขระที่ไม่รู้จักสองตัว
เมื่อนึกถึงข้อมูลพื้นฐานนั้นเราสามารถตอบคำถามที่เฉพาะเจาะจงได้ดังนี้
ฉันต้องการSELECT NCHAR(128512);
กลับเช่นนี้:SELECT N'😀';
สิ่งนี้สามารถเกิดขึ้นได้หากฐานข้อมูลปัจจุบัน - ซึ่งมีการดำเนินการแบบสอบถาม - มีการเรียงหน้าเริ่มต้นที่เป็นตัวอักษรเสริม - เสริมและสิ่งเหล่านั้นถูกนำมาใช้ใน SQL Server 2012 ฟังก์ชั่นในตัวที่มีพารามิเตอร์อินพุตสตริง แบบอินไลน์ผ่านCOLLATE
ข้อ (เช่นLEN(N'string' COLLATE Some_Collation_SC)
) และไม่จำเป็นต้องดำเนินการภายในฐานข้อมูลที่มีการเปรียบเทียบค่าเริ่มต้น SCA อย่างไรก็ตามฟังก์ชันในตัวเช่นNCHAR()
ยอมรับINT
พารามิเตอร์อินพุตและส่วนCOLLATE
คำสั่งไม่ถูกต้องในบริบทนั้น (ซึ่งเป็นเหตุผลที่NCHAR()
รองรับเฉพาะอักขระเสริมเมื่อฐานข้อมูลปัจจุบันมีการเปรียบเทียบค่าเริ่มต้นที่เป็นตัวเสริมอักขระ - แต่นี่เป็นสิ่งที่ไม่จำเป็น ความไม่สะดวกที่สามารถเปลี่ยนแปลงได้ดังนั้นโปรดลงคะแนนสำหรับคำแนะนำของฉัน:ฟังก์ชัน NCHAR () ควรส่งคืนอักขระเสริมสำหรับค่า 0x10000 - 0x10FFFF เสมอโดยไม่คำนึงถึงการเปรียบเทียบค่าเริ่มต้นของฐานข้อมูลที่ใช้งานอยู่ )
มีคำอธิบายว่าทำไมโดยไม่คำนึงถึงการเรียงหน้า SQL Server สามารถเข้าใจและจัดการกับอักขระส่วนขยายยกเว้นจากมุมมองของNCHAR
?
SQL Server สามารถจัดเก็บและรับอักขระเสริมได้อย่างไรโดยไม่มีการสูญหายของข้อมูลได้อธิบายไว้ในส่วนบนสุดของคำตอบนี้ แต่มันไม่เป็นความจริงที่NCHAR
เป็นฟังก์ชันในตัวเดียวที่มีปัญหากับอักขระเสริม (เมื่อไม่ได้ใช้การจัดเรียง SCA) ตัวอย่างเช่นLEN(N'😀' COLLATE SQL_Latin1_General_CP1_CI_AS)
ส่งคืนค่า 2 ในขณะที่LEN(N'😀' COLLATE Latin1_General_100_CI_AS_SC)
ส่งคืนค่า 1
หากคุณไปที่ลิงค์ที่สองที่โพสต์ไว้ในคำถาม (เช่น "ข้อมูลเพิ่มเติมของการจัดเรียงอักขระของ Microsoft") และเลื่อนลงมาเล็กน้อยคุณจะเห็นแผนภูมิของฟังก์ชันในตัวและวิธีการทำงานตามการจัดเรียงที่มีประสิทธิภาพ
ฉันจะค้นหาการเปรียบเทียบที่มีการตั้งค่าสถานะ "อักขระเพิ่มเติม" ได้อย่างไร
ใน SQL Server เวอร์ชันก่อนปี 2012 คุณไม่สามารถทำได้ แต่เริ่มต้นด้วย SQL Server 2012 คุณสามารถใช้แบบสอบถามต่อไปนี้:
SELECT col.*
FROM sys.fn_helpcollations() col
WHERE col.[name] LIKE N'%[_]SC'
OR col.[name] LIKE N'%[_]SC[_]%'
OR (COLLATIONPROPERTY(col.[name], 'Version') = 3
AND col.[name] NOT LIKE N'%[_]BIN%');
ข้อความค้นหาของคุณใกล้แล้ว แต่รูปแบบเริ่มต้นด้วยSQL
และ SQL Server Collations (เช่นที่ขึ้นต้นด้วยSQL_
) ได้ถูกเลิกใช้ไประยะหนึ่งเพื่อสนับสนุนการจัดเรียง Windows (ที่ไม่ได้ขึ้นต้นด้วยSQL_
) ดังนั้นSQL_
Collation จะไม่ได้รับการปรับปรุงและดังนั้นจึงไม่มีรุ่นที่ใหม่กว่าที่จะมี_SC
ตัวเลือก (และเริ่มต้นใน SQL Server 2017 การเปรียบเทียบใหม่ทั้งหมดจะสนับสนุนอักขระเสริมโดยอัตโนมัติและไม่ต้องการหรือมีหรือ_SC
ตั้งค่าสถานะและใช่แบบสอบถาม แสดงทันทีเหนือบัญชีสำหรับสิ่งนั้นรวมถึงการ_UTF8
รวบรวมการเปรียบเทียบที่เพิ่มใน SQL Server 2019)
คุณสามารถติดตั้ง collation บนอินสแตนซ์รุ่นเก่าได้หรือไม่?
ไม่คุณไม่สามารถติดตั้ง Collations ลงใน SQL Server รุ่นก่อนหน้าได้
ฉันจะตั้งค่าตัวแปรสตริง Unicode (เช่น nvarchar) เป็นอักขระเสริมได้โดยใช้รหัส (โดยไม่ใช้อักขระเสริมจริง) ในฐานข้อมูลที่การเรียง "ไม่มีสัญลักษณ์อักขระเสริม (SC)"?
...
ถึงแม้ว่าเซิร์ฟเวอร์คือ SQL Server 2008 R2 แต่ฉันก็ยังสงสัยเกี่ยวกับวิธีแก้ไขปัญหาสำหรับรุ่นที่ใหม่กว่า
เมื่อไม่ได้ใช้การจัดเรียง SCA คุณสามารถฉีดรหัสคะแนนเหนือ 65535 / U + FFFF ได้สองวิธี:
- ระบุคู่ตัวแทนในรูปแบบของการโทรสองครั้งไปยัง
NCHAR()
ฟังก์ชันแต่ละรายการมีส่วนหนึ่งของคู่
- ระบุคู่ตัวแทนในแง่ของการแปลง
VARBINARY
รูปแบบของลำดับไบต์ Little Endian (เช่นย้อนกลับ)
ทั้งสองวิธีของการแทรกอักขระเสริม / คู่ตัวแทนจะทำงานแม้ว่าการจัดเรียงที่มีประสิทธิภาพคือการเสริมอักขระและควรทำงานใน SQL Server ทุกเวอร์ชันอย่างน้อยที่สุดเท่าที่เคยมีมาในปี 2005 (แม้ว่าอาจจะใช้ได้เช่นกัน SQL Server 2000 เช่นกัน)
ตัวอย่าง:
- ตัวอักษร:
💩
- ชื่อ: กองพู
- ทศนิยม: 128169
- จุดรหัส: U + 1F4A9
- คู่ตัวแทน: U + D83D & U + DF21
SELECT N'💩', -- 💩
UNICODE(N'💩' COLLATE Latin1_General_100_CI_AS), -- 55357
UNICODE(N'💩' COLLATE Latin1_General_100_CI_AS_SC), -- 128169
NCHAR(128169), -- 💩 in DB with _SC Collation, else NULL
NCHAR(0x1F4A9), -- 💩 in DB with _SC Collation, else NULL
CONVERT(VARBINARY(4), 128169), -- 0x0001F4A9
CONVERT(VARBINARY(4), N'💩'), -- 0x3DD8A9DC
CONVERT(NVARCHAR(10), 0x3DD8A9DC), -- 💩 (regardless of DB Collation)
NCHAR(0xD83D) + NCHAR(0xDCA9) -- 💩 (regardless of DB Collation)
UPDATE
คุณสามารถใช้ iTVF ต่อไปนี้เพื่อรับค่า Surrogate Pair (ทั้งในINT
และBINARY
แบบฟอร์ม) จากจุดรหัสใด ๆ ระหว่าง 65536 - 1114111 (0x010000 - 0x10FFFF) และในขณะที่พารามิเตอร์อินพุตเป็นประเภทINT
คุณสามารถผ่านในรูปแบบไบนารี / ฐานสิบหกของจุดรหัสและมันจะแปลงเป็นค่าจำนวนเต็มที่ถูกต้องโดยปริยาย
CREATE FUNCTION dbo.GetSupplementaryCharacterInfo(@CodePoint INT)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN
WITH calc AS
(
SELECT 55232 + (@CodePoint / 1024) AS [HighSurrogateINT],
56320 + (@CodePoint % 1024) AS [LowSurrogateINT]
WHERE @CodePoint BETWEEN 65536 AND 1114111
)
SELECT @CodePoint AS [CodePointINT],
HighSurrogateINT,
LowSurrogateINT,
CONVERT(VARBINARY(3), @CodePoint) AS [CodePointBIN],
CONVERT(BINARY(2), HighSurrogateINT) AS [HighSurrogateBIN],
CONVERT(BINARY(2), LowSurrogateINT) AS [LowSurrogateBIN],
CONVERT(binary(4), NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT)) AS [UTF-16LE],
NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT) AS [Character]
FROM calc;
GO
ใช้ฟังก์ชั่นด้านบนทั้งสองแบบสอบถามต่อไปนี้:
SELECT * FROM dbo.GetSupplementaryCharacterInfo(128169);
SELECT * FROM dbo.GetSupplementaryCharacterInfo(0x01F4A9);
ทั้งคืนค่าต่อไปนี้:
CodePoint HighSurrogate LowSurrgate CodePoint HighSurrgate LowSurrgate UTF-16LE Char
INT INT INT BIN BIN BIN actr
128169 55357 56489 0x01F4A9 0xD83D 0xDCA9 0x3DD8A9DC 💩
อัพเดต 2: การปรับปรุงที่ดียิ่งขึ้น!
ฉันได้ปรับ iTVF ที่แสดงด้านบนเป็นตอนนี้กลับจุดรหัส 188,657 ดังนั้นคุณไม่จำเป็นต้องให้พอดีกับค่าใด ๆ แน่นอนว่าในฐานะ TVF คุณสามารถเพิ่มส่วนWHERE
คำสั่งเพื่อกรองจุดรหัสเฉพาะหรือช่วงของรหัสจุดหรือ "ตัวละครที่คล้ายกัน" เป็นต้นและจะมีคอลัมน์เพิ่มเติมที่มีลำดับการหลีกเลี่ยงที่จัดรูปแบบไว้ล่วงหน้าเพื่อสร้างแต่ละรหัส จุด (ทั้ง BMP และอักขระเสริม) ใน T-SQL, HTML และ C-style (เช่น\xHHHH
) อ่านทั้งหมดได้ที่นี่:
เคล็ดลับ SSMS # 3: เข้าถึง / ค้นคว้าอักขระ Unicode ทั้งหมดได้อย่างง่ายดาย (ใช่รวมถึง Emojis 😸)