Автоматический перевод при преобразовании Unicode в не-Unicode / NVARCHAR в VARCHAR

8

Кодовая точка Unicode 9619 - это символ под названием «Темная тень»: ( http://unicode-table.com/en/search/?q=9619 ).

Используя параметры SQL_Latin1_General_CP1_CI_ASсортировки и кодовую страницу 1252, я ожидал бы, что приведение / преобразование этого символа Unicode в тип данных не-Unicode приведет к появлению вопросительного знака ( ?), поскольку кодовая страница 1252 не содержит этот символ, и это похоже на SQL Server поведение при конверсии не может иметь место.

Поэтому мой вопрос: почему SQL Server преобразует этот символ в коде ASCII 166 , который является «Pipe, Разбитая вертикальная черта»: ¦?

SELECT NCHAR(9619), CAST(NCHAR(9619) AS CHAR(1)), ASCII(CAST(NCHAR(9619) AS CHAR(1)))
Генри Ли
источник
3
SQL Server использует то, что в этой статье называется гомоглифическим преобразованием, и часто преобразует символы, которые не могут быть представлены, в близкие эквиваленты. Например, потеря акцента на персонаже или замена умных цитат на простые. Я согласен, что это не выглядит очень близко, хотя! Я не уверен, если или где эти преобразования задокументированы.
Мартин Смит
Вау, понятия не имел ... Боже, просто не кажется правильным ... это не тот же персонаж. Почему бы просто не "... упс, такой символ не найден в этой кодовой странице ..." и не выполнить преобразование?
Генри Ли
1
Просто читал эту страницу и запомнил это. Не уверен, что SQL Server использует точно такие же алгоритмы «наилучшего соответствия».
Мартин Смит,
1
@MartinSmith, если вы не уверены, что сопоставления «лучше всего подходят» для SQL Server, смотрите мой ответ ниже, когда я нашел эти сопоставления :-).
Соломон Руцки

Ответы:

8

Почему SQL преобразует Unicode 9619 в код ASCII 166?

SQL Server здесь не использует никакой специальной пользовательской логики; он использует стандартные службы операционной системы для выполнения преобразования.

В частности, тип SQL Server и выражение service ( sqlTsEs) обращаются к подпрограмме ОС WideCharToMultiByteв kernel32.dll. SQL Server устанавливает входные параметры WideCharToMultiByteтак, чтобы подпрограмма выполняла «быстрый перевод». Это быстрее, чем запросить использование определенного символа по умолчанию, если прямой перевод не существует.

Быстрый перевод опирается на целевую кодовую страницу, чтобы выполнить сопоставление наилучшим образом для любых непревзойденных символов, как упомянуто в ссылке, которую Мартин Смит предоставил в комментарии к вопросу:

Наиболее подходящие стратегии различаются для разных кодовых страниц, и они подробно не документированы.

Когда входные параметры установлены для быстрого перевода, WideCharToMultiByteвызывается служба ОС GetMBNoDefault( источник ). Проверка стека вызовов SQL Server при выполнении преобразования, указанного в вопросе, подтверждает это:

Трассировка стека SQL Server

Пол Уайт 9
источник
7

Преобразование данных Unicode в конкретную кодовую страницу использует так называемую стратегию «наилучшего соответствия» (как отмечено в ответе @ Paul и по ссылке, которую @Martin отметил в комментарии к Вопросу). Согласно этой странице MSDN для кодировки символов в .NET Framework :

Наилучшее соответствие - это поведение по умолчанию для объекта Encoding, который кодирует данные Unicode в данные кодовой страницы ...

Но что именно эти отображения? Эта страница MSDN используется заявить следующее:

Наиболее подходящие стратегии различаются для разных кодовых страниц, и они подробно не документированы.

Однако это было не совсем правильно. Возможно, «стратегии» определения отображений точно не задокументированы. Хорошо. Но, отображения сами являются документированные, просто не в самых простых местах , чтобы найти.

Итак, благодаря Microsoft, переместившей документацию на GitHub, эта страница теперь гласит следующее (потому что я обновил ее 😸):

Наиболее подходящие стратегии подробно не документированы. Тем не менее, несколько кодовых страниц задокументированы на веб-сайте Консорциума Unicode . Пожалуйста, просмотрите файл readme.txt в этой папке для описания того, как интерпретировать файлы сопоставления.

Если вы перейдете по следующему URL-адресу, вы увидите список из нескольких файлов, каждый из которых назван для кодовой страницы, в которую он отображает символы Unicode:

ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/

Большинство файлов были в последний раз обновлены (или, по крайней мере, размещены там) 2006-10-04, а один из них был обновлен 2012-03-14. Первая часть этих файлов отображает коды ASCII в эквивалентную кодовую точку Unicode. Но вторая часть каждого файла отображает символы Unicode в их «эквиваленты» ASCII.

Я написал тестовый скрипт, который использует сопоставления Кодовой страницы, чтобы проверить, действительно ли SQL Server использует эти сопоставления. Это можно определить, ответив на эти два вопроса:

  1. Для всех сопоставленных точек кода SQL Server преобразует их в указанные сопоставления?
  2. Для всех не отображенных кодовых точек SQL Server преобразует любой из них в не " ?" символ?

Тестовый скрипт слишком длинный, чтобы разместить его здесь, поэтому я разместил его на Pastebin по адресу:

Unicode для сопоставления кодовых страниц в SQL Server

Запуск сценария покажет, что ответом на первый вопрос выше является «Да» (что означает, что все предоставленные сопоставления соблюдаются). Это также покажет, что ответом на второй вопрос является «Нет» (то есть ни один из не нанесенных на карту кодовых точек не превращается ни во что, кроме символа «неизвестный»). Следовательно, этот файл отображения очень точный :-).

Соломон Руцкий
источник