Проблема кодування із стовпцем VARCHAR SQL Server, отриманим у Python


10

Нещодавно у нас виникла проблема з кодуванням, пов’язаним із полем, яке зберігається як varchar (120) у SQL Server. У SSMS varchar з'являється як:

"Хто вбив Джонбена?"

Однак, коли він введений у python, він виглядає як:

введіть тут опис зображення

Я досліджував це з боку Python, і нічого дивного не відбувається. Моя теорія полягає в тому, що varchar в SQL Server приймає символи UTF-8, які відображаються в python інакше, ніж SSMS. Я не дуже знайомий з кодуванням в SQL Server. Може хтось, будь ласка, дайте мені знати наступне:

  • Чи існує спосіб у SSMS переглянути кодування варчара? Наприклад, бачите \ x82 замість того, щоб відображати кому, як це зараз у SSMS?
  • Ми використовуємо SQL Server 2008. Чи є спосіб змінити кодування будь-яких символів UTF-8 на символи ASCII без використання інструментів імпорту / експорту чи скидання до плоского файлу? Тобто я можу здійснити це перетворення за допомогою запиту?
  • Чи є спосіб програмного виявлення проблемних записів за допомогою запиту (проблематичний визначається як символи UTF-8, які не підтримуються через ASCII)?

Заздалегідь спасибі!

Використання sp_help N'table_name';я виявив , що Впорядкування цього VARCHARстовпця: SQL_Latin1_General_CP1_CI_AS.


Яке зіставлення використовує цей VARCHARстовпець?
Соломон Руцький

@SolomonRutzky як ви перевіряєте порівняння. Я не впевнений, що це навіть означає
Ерік

Найшвидший спосіб я думаю: sp_help N'table_name';. Подивіться на стовпчик на основі "ім'я", а потім подивіться на стовпець "collation_name".
Соломон Руцький

@SolomonRutzky порівняння для цього поля - "SQL_Latin1_General_CP1_CI_AS"
Ерік

Відповіді:


17

SQL Server ні за яких обставин не зберігає UTF-8. Ви отримуєте або UTF-16 Little Endian (LE) з допомогою NVARCHAR( в тому числі NCHARі NTEXT, але ніколи не використовувати NTEXT) і XML, або деякі 8-бітна кодування, на основі кодової сторінки, з допомогою VARCHAR( в тому числі CHARі TEXT, але ніколи не використовувати TEXT) .

Проблема тут полягає в тому, що ваш код неправильно перекладає цей символ 0x82, думаючи, що це UTF-8, але це не так. Немає символу UTF-8, який має значення 0x82, тому ви отримуєте символ "невідомо" / заміну " ". Будь ласка, дивіться таку таблицю UTF-8, яка показує, що для однобайта 0x82 немає символу:

Таблиця кодування UTF-8

Як заявлено в ОП, зіставлення стовпця SQL_Latin1_General_CP1_CI_AS, про який йде мова , означає, що для 8-бітового кодування використовується код Code 1252, який є Windows Latin 1 (ANSI) . І перевірка цієї діаграми (прокрутіть до нижньої діаграми, оскільки вона має імена символів) значення 0x82 (шукайте "82" у стовпці "Кодова точка") насправді є Єдиною котирувальною маркою Low-9, яку ви бачите в SSMS. Цей символ в UTF-8, являє собою послідовність 3 байт: E2 80 9A.

Що все це означає: ваш код Python повинен або встановити кодування клієнта для підключення SQL Server до коду сторінки 1252, або вам потрібно змінити / перетворити кодування повернутої рядка з коду сторінки 1252 в UTF-8.

Звичайно, якщо це відображається на веб-сторінці, ви можете змінити заявлену діаграму сторінки, якою є Windows-1252, але це може заважати іншим символам на сторінці, якщо там вже є символи UTF-8.


Приємно, це дуже корисно, дякую Соломоне. Будь ласка, дайте мені знати про переклад. Це досить хитра проблема, і я навіть не впевнений, з чого почати.
Ерік

Ух, дивовижна деталь, @Solomon! Я приїхав сюди, шукаючи іншу проблему Python + MS SQL, але читав, бо я так багато вчився. :-P
Майк Вільямсон

1
@MikeWilliamson Дякую за те, що поділився цим компліментом :). Ви також можете бути зацікавлені в наступних: TSQL md5 хеш відрізняється від C # .NET md5 (на SO), Як Strip іврит Accent Marks (тут на DBA.SE), і Collations.Info . Насолоджуйтесь!
Соломон Руцький

Дякую! Я підозрюю, що хтось, хто працює з не латинською мовою, знає цей матеріал набагато краще, ніж хтось із нас блаженно працює в США / Великобританії. :)
Майк Вільямсон

1
Лише зауваження: MS SQL Server 2019 представляє вбудовану підтримку UTF-8 у типах даних VARCHAR / CHAR.
Григорій Ареній
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.