Здесь необходимо сделать несколько пояснений относительно фрагментов документации MS, размещенных в вопросе, а также примера кода, самих вопросов и утверждений, сделанных в комментариях к вопросу. Я полагаю, что большую часть путаницы можно прояснить с помощью информации, представленной в следующем моем посте:
Перво-наперво (это единственный способ, которым это может быть, верно?): я не оскорбляю людей, которые написали документацию по MS, поскольку SQL Server сам по себе является огромным продуктом, и есть много чего, что нужно сделать. обложка и т. д., но на данный момент (пока у меня не будет возможности обновить ее), пожалуйста, прочитайте официальную документацию с чувством осторожности. Есть несколько неверных утверждений относительно Collations/Unicode.
UCS-2 — это кодировка, которая обрабатывает подмножество набора символов Unicode. Он работает в 2-байтовых блоках. С помощью 2 байтов вы можете кодировать значения от 0 до 65535. Этот диапазон кодовых точек известен как BMP (базовая многоязычная плоскость). BMP — это все символы, которые не являются дополнительными символами (поскольку они дополняют BMP), но содержат набор кодовых точек, которые используются исключительно для кодировать дополнительные символы в UTF-16 (т. е. 2048 суррогатных кодовых точек). Это полное подмножество UTF-16.
UTF-16 — это кодировка, которая обрабатывает весь набор символов Unicode. Он также работает с 2-байтовыми блоками. На самом деле нет никакой разницы между UCS-2 и UTF-16 в отношении кодовых точек и символов BMP. Разница в том, что UTF-16 использует эти 2048 суррогатных кодовых точек в BMP для создания суррогатных пар, которые являются кодировками для всех дополнительных символов. Хотя дополнительные символы имеют размер 4 байта (в UTF-8, UTF-16 и UTF-32), на самом деле они представляют собой две 2-байтовые единицы кода при кодировании в UTF-16 (аналогично, они четыре 1-байтовых блока в UTF-8 и один 4-байтовый в UTF-32).
Поскольку UTF-16 просто расширяет возможности UCS-2 (фактически определяя использование суррогатных кодовых точек), нет абсолютно никакой разницы в последовательностях байтов, которые можно хранить. в любом случае. Все 2048 суррогатных кодовых точек, используемых для создания дополнительных символов в UTF-16, являются допустимыми кодовыми точками в UCS-2, они просто не имеют определенного использования (т. е. интерпретации) в UCS-2.
NVARCHAR
, NCHAR
и устаревшие типы данных "так-не-используйте-это-NTEXT
" хранят символы Unicode, закодированные в UCS-2/UTF-16. С точки зрения хранения нет абсолютно никакой разницы. Таким образом, не имеет значения, если что-то (даже за пределами SQL Server) говорит, что может хранить UCS-2. Если он может это сделать, то он по своей сути может хранить UTF-16. На самом деле, хотя у меня не было возможности обновить сообщение, указанное выше, я смог сохранить и получить, как и ожидалось, смайлики (большинство из которых являются дополнительными символами) в SQL Server 2000, работающем в Windows XP. Я думаю, что до 2003 года не было определено никаких дополнительных символов, и уж точно не до 1999 года, когда разрабатывался SQL Server 2000. На самом деле (опять же) UCS-2 использовался только в Windows / SQL Server, потому что Microsoft продвинулась вперед в разработке до того, как UTF-16 была завершена и опубликована (и как только это было, UCS-2 устарел).
Единственная разница между UCS-2 и UTF-16 заключается в том, что UTF-16 знает, как интерпретировать суррогатные пары (состоящие из пары суррогатных кодовых точек, поэтому, по крайней мере, они имеют соответствующие имена). Именно здесь вступают в действие параметры сортировки _SC
(и, начиная с SQL Server 2017, также параметры сортировки версии _140_
, которые включают поддержку дополнительных символов, поэтому ни один из них не имеет _SC
в своем имени): они позволяют встроенным функциям SQL Server правильно интерпретировать дополнительные символы. Вот и все! Эти параметры сортировки не имеют ничего общего с хранением и извлечением дополнительных символов, и они даже не имеют ничего общего с их сортировкой или сравнением (хотя в документации по параметрам сортировки и поддержке Unicode говорится в частности, это то, что делают эти сопоставления — еще один пункт в моем списке дел, который нужно исправить). Для параметров сортировки, в имени которых нет ни _SC
, ни _140_
(хотя новое в SQL Server 2019 Latin1_General_100_BIN2_UTF8
может быть серой областью, по крайней мере, я помню, что было некоторое несоответствие либо там, либо с сопоставления Japanese_*_140_BIN2
), встроенные функции обрабатывают только кодовые точки BMP (т. е. UCS-2).
Отсутствие обработки дополнительных символов означает, что допустимая последовательность из двух суррогатных кодовых точек не интерпретируется как единая дополнительная кодовая точка. Таким образом, для сопоставлений, отличных от SC, суррогатная кодовая точка BMP 1 (B1) и суррогатная кодовая точка BMP 2 (B2) — это просто те две кодовые точки, ни одна из которых не определена, поэтому они отображаются как два нуля (т. е. B1, за которым следует БИ 2). Вот почему можно разделить дополнительный символ на два, используя SUBSTRING
/ LEFT
/ RIGHT
, потому что они не будут знать, как сохранить эти две кодовые точки BMP вместе. Но сопоставление SC прочитает эти кодовые точки B1 и B2 с диска или памяти и увидит одну дополнительную кодовую точку S. Теперь ее можно правильно обработать через SUBSTRING
/ CHARINDEX
/ и т. д.
Функция NCHAR()
(не тип данных; да, плохо названная функция;) также чувствительна к тому, поддерживает ли сопоставление по умолчанию текущей базы данных дополнительные символы. Если да, то передача значения от 65536 до 1114111 (диапазон дополнительных символов) вернет значение, отличное от NULL
. Если нет, то передача любого значения выше 65535 вернет NULL
. (Конечно, было бы намного лучше, если бы NCHAR()
всегда работало, учитывая, что сохранение/извлечение всегда работает, поэтому, пожалуйста, проголосуйте за это предложение: Функция NCHAR() должна всегда возвращать дополнительный символ для значений 0x10000 - 0x10FFFF независимо от сортировки активной базы данных по умолчанию ) .
К счастью, вам не нужна сортировка SC для вывода дополнительного символа. Вы можете либо вставить литеральный символ, либо преобразовать суррогатную пару в кодировке UTF-16 Little Endian, либо использовать функцию NCHAR()
для вывода суррогатной пары. Следующее работает в SQL Server 2000 (с использованием SSMS 2005), работающем в Windows XP:
SELECT N'????', -- ????
CONVERT(VARBINARY(4), N'????'), -- 0x3DD8A9DC
CONVERT(NVARCHAR(10), 0x3DD8A9DC), -- ???? (regardless of DB Collation)
NCHAR(0xD83D) + NCHAR(0xDCA9) -- ???? (regardless of DB Collation)
Дополнительные сведения о создании дополнительных символов при использовании сопоставлений, отличных от SC, см. в моем ответе на следующий вопрос DBA.SE: Как сделать Я установил строку Unicode/NVARCHAR для SQL Server в эмодзи или дополнительный символ?
Ничто из этого не влияет на то, что вы видите. Если вы храните кодовую точку, то она есть. Его поведение — сортировка, сравнение и т. д. — контролируется параметрами сортировки. Но то, как это выглядит, контролируется шрифтами и ОС. Ни один шрифт не может содержать все символы, поэтому разные шрифты содержат разные наборы символов, причем наиболее часто используемые символы часто перекрываются. Однако, если шрифт имеет сопоставленную последовательность байтов, он может отображать этот символ. Вот почему единственная работа, необходимая для правильного отображения дополнительных символов в SQL Server 2000 (с использованием SSMS 2005), работающем в Windows XP, заключалась в добавлении шрифта, содержащего символы, и внесении одного или двух незначительных изменений в реестр (без изменений в SQL Server).
Дополнительные символы в SQL_*
сопоставлениях и сопоставлениях без номера версии в имени не имеют весов сортировки. Следовательно, все они приравниваются друг к другу, а также к любым другим кодовым точкам BMP, которые не имеют весов сортировки (включая пробел (U+0020) и ноль (U+0000)). Это начали исправлять в версии _90_
collations.
SSMS не имеет ничего общего со всем этим, за исключением возможной необходимости замены шрифта, используемого для редактора запросов и/или результатов сетки, и/или сообщений об ошибках + на шрифт с нужными символами. (SSMS не отображает ничего за пределами, возможно, пространственных данных; символы визуализируются драйвером дисплея + определениями шрифтов +, возможно, чем-то еще).
и бессмысленно, и неправильно. Вероятно, они имели в виду, что типы данных будут хранить только подмножество кодировки UTF-16 (поскольку UCS-2 является подмножеством). Кроме того, даже если в нем указана кодировка символов UTF-16, это все равно будет неправильно, потому что байты, которые вы передаете, будут сохранены (при условии достаточного свободного места в столбце или переменной).