ฉันจะตั้งค่าสตริง SQL Unicode / NVARCHAR ของเซิร์ฟเวอร์เป็นอีโมจิหรืออักขระเสริมได้อย่างไร


23

ฉันต้องการตั้งค่าตัวแปรสตริง Unicode เป็นอักขระเฉพาะตามจุดโค้ด Unicode

ฉันต้องการใช้จุดรหัสเกิน 65535 แต่ฐานข้อมูล SQL Server 2008 R2 SQL_Latin1_General_CP1_CI_ASมีการเปรียบเทียบของ

ตามเอกสาร NCHAR ไมโครซอฟท์ที่NCHARฟังก์ชั่นใช้เวลาจำนวนเต็มดังนี้

integer_expression

เมื่อการเรียงของฐานข้อมูลไม่มีค่าสถานะอักขระเสริม (SC) นี่เป็นจำนวนเต็มบวกตั้งแต่ 0 ถึง 65535 (0 ถึง 0xFFFF) หากระบุค่านอกช่วงนี้ NULL จะถูกส่งคืน สำหรับข้อมูลเพิ่มเติมเกี่ยวกับอักขระเสริมดูที่การเรียงหน้าและการสนับสนุน Unicode

เมื่อการเรียงฐานข้อมูลสนับสนุนแฟล็กอักขระเสริม (SC) นี่เป็นจำนวนเต็มบวกตั้งแต่ 0 ถึง 1114111 (0 ถึง 0x10FFFF) หากระบุค่านอกช่วงนี้ NULL จะถูกส่งคืน

ดังนั้นรหัสนี้:

SELECT NCHAR(128512);

ส่งคืนNULLในฐานข้อมูลนี้

ฉันต้องการให้ส่งคืนเช่นนี้:

SELECT N'😀';

ฉันจะตั้งค่าตัวแปรสตริง Unicode (เช่น nvarchar) เป็น emoji โดยใช้รหัสได้อย่างไร (โดยไม่ต้องใช้อักขระ emoji จริง) ในฐานข้อมูลที่การเรียง "ไม่มีตัวอักขระเสริม (SC)"

รายการเต็มของคะแนนรหัส emoji Unicode

(ท้ายที่สุดฉันต้องการให้ตัวละครทำงานได้ฉันเลือกอิโมจิเพื่อความสะดวกในการอ้างอิง)

(แม้ว่าเซิร์ฟเวอร์จะเป็น SQL Server 2008 R2 แต่ฉันก็ยังสงสัยเกี่ยวกับวิธีแก้ไขปัญหาสำหรับรุ่นที่ใหม่กว่า)

สมมติว่าไม่มีวิธีใดฉันสามารถอ้างอิงฟังก์ชันที่ผู้ใช้กำหนดเองแบบอินไลน์ในฐานข้อมูลอื่นที่มีการเปรียบเทียบที่เหมาะสมหรือไม่

ฉันจะค้นหาการเปรียบเทียบที่มีการตั้งค่าสถานะ "อักขระเพิ่มเติม" ได้อย่างไร

สิ่งนี้จะไม่ส่งคืนบันทึกบนเซิร์ฟเวอร์ของเรา:

SELECT * FROM sys.fn_helpcollations() 
WHERE name LIKE 'SQL%[_]SC';

ดูเหมือนว่า SQL Server 2012 จะเปิดตัวLatin1_General_100_CI_AS_SCซึ่งจะใช้งานได้ คุณสามารถติดตั้ง collation บนอินสแตนซ์ที่เก่ากว่าได้หรือไม่?

การอ้างอิงการเรียง:

มีคำอธิบายว่าทำไมโดยไม่คำนึงถึงการเรียงหน้า SQL Server สามารถเข้าใจและจัดการกับอักขระส่วนขยายยกเว้นจากมุมมองของNCHAR?


ขอบคุณสำหรับข้อมูลเพิ่มเติมที่ครอบคลุม ฉันไม่พบปัญหานี้อีกต่อไป แต่ฉันจะเก็บข้อมูลนี้ไว้ในที่คั่นหน้าใจ
Riley Major

1
ไม่มีปัญหา. ฉันไม่คิดว่าคุณยังต้องการบางสิ่งบางอย่างเพียงเพื่อคุณจะได้ชื่นชม / สามารถใช้ประโยชน์จากการปรับตัว ...
โซโลมอน Rutzky

คำตอบ:


36

การเข้ารหัส 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:

  1. หลายฟังก์ชั่น (ไม่เพียง แต่NCHAR()) ไม่จัดการคู่ตัวแทน / ตัวละครเสริมเมื่อไม่ได้ใช้เสริม Character-Aware เปรียบเทียบ (SCA นั่นคือหนึ่งเดียวกับ_SC, หรือ _140_แต่ไม่_BIN*ในชื่อ) เพราะไม่ใช่ SCA Collations (โดยเฉพาะอย่างยิ่งSQL_การจัดเรียง) ถูกนำมาใช้ก่อนที่ UTF-16 จะแล้วเสร็จ (บางครั้งในปี 2000 ฉันเชื่อ) ไม่ใช่การSQL_เรียงที่มี_90_หรือ_100_ในชื่อของพวกเขา แต่ไม่_SCได้รับการสนับสนุนขั้นต่ำสำหรับอักขระเสริมในแง่ของการเปรียบเทียบและการเรียงลำดับ
  2. ชุดอักขระ Unicode / UTF-16 แบบเต็มสามารถจัดเก็บได้โดยไม่สูญเสียข้อมูลใด ๆ ในNVARCHAR/ NCHAR/ XML/ NTEXTdatatypes เนื่องจาก 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 ได้สองวิธี:

  1. ระบุคู่ตัวแทนในรูปแบบของการโทรสองครั้งไปยังNCHAR()ฟังก์ชันแต่ละรายการมีส่วนหนึ่งของคู่
  2. ระบุคู่ตัวแทนในแง่ของการแปลง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 😸)


1
สุดยอดการทำงานของโซโลมอน! คำอธิบายที่ดีเลิศ
Ronen Ariely
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.