Як встановити рядок Unicode / NVARCHAR SQL Server на смайлик або додатковий символ?


23

Я хочу встановити змінну рядка Unicode для конкретного символу на основі його кодової точки Unicode.

Я хочу використовувати кодову точку за межами 65535, але база даних SQL Server 2008 R2 має поєднання SQL_Latin1_General_CP1_CI_AS.

Згідно з документацією Microsoft 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) на смайлик, використовуючи код (без використання фактичного символу емоджи) у базі даних, де зіставлення "не містить прапора додаткового символу (SC)"?

Повний список кодів емоджи Unicode

(Зрештою, я хочу, щоб будь-який персонаж працював. Я просто вибрав смайли для зручності.)

(Хоча сервером є SQL Server 2008 R2, мені також цікаво будь-яке рішення для пізніших версій.)

Якщо припустити, що немає ніякого способу, чи можу я вказати функцію, що визначається вбудованим користувачем, в іншій базі даних, яка мала відповідне зіставлення?

Як знайти посилання, який має прапор "додатковий символ"?

Це не повертає записів на нашому сервері:

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

Схоже, введено SQL Server 2012, Latin1_General_100_CI_AS_SCякий би працював. Чи можете ви встановити посилання на більш старі екземпляри?

Довідкові дані про зіставлення:

Чи є пояснення, чому незалежно від зіставлення SQL Server може розуміти та мати справу з розширеними символами, за винятком точки зору NCHAR?


Дякуємо за вичерпну додаткову інформацію. Я більше не стикаюся з цим питанням, але я зберігатиму цю інформацію по місту.
Райлі майор

1
Без проблем. Я не думав, що ти все ще щось потребуєш , просто щоб ти оцінив / зможеш скористатися адаптацією ...
Соломон Руцький,

Відповіді:


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). І, діапазон UTF-16 65536 - 1114111 (0x10000 - 0x10FFFF) побудований з двох точок коду в діапазоні UCS-2 (діапазони 0xD800 - 0xDBFF та 0xDC00 - 0xDFFF, спеціально), які були зарезервовані для цієї мети, інакше не мають значення. Ця комбінація двох точок коду відома як пара сурогатних пар, а сурогатні пари представляють символи, що виходять за межі діапазону UCS-2, які відомі як додаткові символи.

Вся ця інформація пояснює два аспекти NVARCHAR / Unicode даних у SQL Server:

  1. Кілька вбудованих функцій (не тільки NCHAR()) не обробляти сурогатних пар / додаткові символи , якщо не використовується додатковий символ-Aware Collation (SCA, тобто один з _SC, або _140_ , але не _BIN*в назві) , бо не-SCA Параметри сортування (особливо SQL_Збірники) спочатку були здійснені до завершення UTF-16 (я вважаю, десь у 2000 році). До неочевидним SQL_параметрам сортування , які мають _90_або _100_в їхніх іменах , але не _SCмає мінімальну підтримку для додаткових символів з точкою зору порівняння і сортування.
  2. Повний Unicode / UTF-16 набір символів може бути збережений, без яких - або втрат даних, в NVARCHAR/ NCHAR/ XML/ NTEXTтипах даних , оскільки UCS-2 і UTF-16 має точно таку ж сукупність електронних даних. Єдина відмінність полягає в тому, що UTF-16 використовує сурогатні кодові точки для побудови сурогатних пар, а UCS-2 просто не може зіставити їх з будь-якими символами, отже, вони з'являються у вбудованих функціях як два невідомих символи.

Маючи на увазі цю основну інформацію, тепер ми можемо переглядати конкретні питання:

Я хотів би SELECT NCHAR(128512);повернути те саме, що і таке:SELECT N'😀';

Це може статися лише в тому випадку, якщо в поточній базі даних, де виконується запит, є за замовчуванням зіставлення, яке є додатковим символом, і вони були введені в SQL Server 2012. Вбудовані функції, які мають параметри введення рядків, можуть містити збірку inline за допомогою COLLATEпункту (тобто LEN(N'string' COLLATE Some_Collation_SC)), і його не потрібно виконувати в Базі даних, яка має зіставлення SCA за замовчуванням. Однак вбудовані функції, такі як NCHAR()прийняти INTвхідний параметр, і COLLATEпункт не є дійсним у цьому контексті (саме тому NCHAR()підтримує додаткові символи, коли в поточній базі даних є порівняння за замовчуванням, яке є додатковим символом; але це зайве незручності, які можна змінити, тому, будь ласка, проголосуйте за мою пропозицію:Функція NCHAR () завжди повинна повертати Додатковий символ для значень 0x10000 - 0x10FFFF незалежно від активного зіставлення бази даних за замовчуванням ).

Чи є пояснення, чому незалежно від зіставлення SQL Server може розуміти та мати справу з розширеними символами, за винятком точки зору NCHAR?

Як SQL Server може зберігати та отримувати додаткові символи без втрати даних, було пояснено у верхньому розділі цієї відповіді. Але це неправда, що NCHARце єдина вбудована функція, яка має проблеми із додатковими символами (коли не використовується SCA Collation). Наприклад, LEN(N'😀' COLLATE SQL_Latin1_General_CP1_CI_AS)повертає значення 2, тоді як LEN(N'😀' COLLATE Latin1_General_100_CI_AS_SC)повертає значення 1.

Якщо ви перейдете до другого посилання, розміщеного у запитанні (тобто "Інформація про додаткові символи зібрання символів Майкрософт") і прокрутіть лише трохи вниз, ви побачите діаграму вбудованих функцій та те, як вони ведуть себе на основі ефективного зібрання.

Як знайти посилання, який має прапор "додатковий символ"?

У версії 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 (тобто ті, що починаються з SQL_) на деякий час застаріли на користь збірників Windows (тих, що не починаються з SQL_). Таким чином, SQL_зібрання не оновлюються, а отже, немає новіших версій, які включали б _SCопцію (і починаючи з SQL Server 2017, усі нові зібрання автоматично підтримують додаткові символи і не потребують або мають _SCпрапор; і так, запит показано одразу вище для цього, а також підбору _UTF8порівнянь, доданих у SQL Server 2019).

Чи можете ви встановити посилання на більш старі екземпляри?

Ні, ви не можете встановити Collations у попередній версії SQL Server.

Як я можу встановити змінну рядка Unicode (наприклад, nvarchar) на Додатковий символ за допомогою коду (без використання фактичного додаткового символу) у базі даних, де порівняння "не містить прапор додаткового символу (SC)"?
...
Хоча сервером є SQL Server 2008 R2, мені також цікаво будь-яке рішення для пізніших версій.

Якщо не використовується SCA Collation, ви можете вводити кодові точки вище 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)

ОНОВЛЕННЯ

Ви можете використовувати наступні iTVF, щоб отримати значення сурогатної пари ( 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 (тобто \xHHHH). Про це читайте тут:

Порада №3 SSMS: Легкий доступ / дослідження ВСІХ символів Unicode (Так, включаючи Emojis 😸)


1
Чудова робота Соломона! Дивовижне пояснення
Ronen Ariely
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.