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