Как мне установить строку SQL Server Unicode / NVARCHAR для эмодзи или дополнительного символа?

23

Я хочу установить строковую переменную Unicode для конкретного символа на основе ее кодовой точки Unicode.

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

Согласно документации NCHAR от Microsoft , 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). И, диапазон 65536 - 1114111 (0x10000 - 0x10FFFF) UTF-16 состоит из двух кодовых точек в диапазоне 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. Встроенные функции, которые имеют строковые входные параметры, могут иметь сопоставление встроенный через 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 (то есть те, которые начинаются с SQL_) на некоторое время устарели в пользу параметров сравнения Windows (те, которые не начинаются с SQL_). Таким образом, параметры SQL_сортировки не обновляются и, следовательно, не имеют более новых версий, которые включали бы этот _SCпараметр (и начиная с SQL Server 2017 все новые параметры сортировки автоматически поддерживают дополнительные символы и не требуют или не имеют _SCфлаг; и да, запрос это показано выше, учитывает это, а также _UTF8подборку сопоставлений, добавленных в SQL Server 2019).

Можете ли вы установить сопоставления на более старых экземплярах?

Нет, вы не можете установить параметры сортировки в предыдущую версию 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)

ОБНОВИТЬ

Вы можете использовать следующую функцию 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предложение для фильтрации по определенной кодовой точке, или диапазону кодовых точек, или «схожим символам» и т. Д. Кроме того, он включает дополнительные столбцы с предварительно отформатированными escape-последовательностями для построения каждого кода. точка (как BMP, так и дополнительные символы) в T-SQL, HTML и C-стиле (т.е. \xHHHH). Прочтите все об этом здесь:

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

Соломон Руцкий
источник
1
Отличная работа Соломона! Потрясающее объяснение
Ронен Арили