Кодування 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:
- Кілька вбудованих функцій (не тільки
NCHAR()
) не обробляти сурогатних пар / додаткові символи , якщо не використовується додатковий символ-Aware Collation (SCA, тобто один з _SC
, або _140_
, але не _BIN*
в назві) , бо не-SCA Параметри сортування (особливо SQL_
Збірники) спочатку були здійснені до завершення UTF-16 (я вважаю, десь у 2000 році). До неочевидним SQL_
параметрам сортування , які мають _90_
або _100_
в їхніх іменах , але не _SC
має мінімальну підтримку для додаткових символів з точкою зору порівняння і сортування.
- Повний 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 двома способами:
- Вкажіть сурогатну пару з точки зору двох викликів
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)
ОНОВЛЕННЯ
Ви можете використовувати наступні 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 😸)