Codierungsproblem mit der in Python abgerufenen SQL Server VARCHAR-Spalte

10

Wir hatten kürzlich ein Problem mit der Codierung in Bezug auf ein Feld, das als varchar (120) in SQL Server gespeichert wird. In SSMS wird der Varchar wie folgt angezeigt:

"Wer hat JonBen getötet?"

Wenn es jedoch in Python gebracht wird, sieht es so aus:

Geben Sie hier die Bildbeschreibung ein

Ich habe dies von der Python-Seite aus untersucht, und nichts Seltsames ist los. Meine Theorie ist, dass der Varchar in SQL Server UTF-8-Zeichen akzeptiert, die in Python anders angezeigt werden als in SSMS. Ich bin mit der Codierung in SQL Server nicht sehr vertraut. Kann mir bitte jemand folgendes mitteilen:

  • Gibt es in SSMS eine Möglichkeit, die Codierung des Varchars anzuzeigen? Siehe zum Beispiel \ x82, anstatt das Komma anzuzeigen, wie es derzeit von SSMS stammt.
  • Wir verwenden SQL Server 2008. Gibt es eine Möglichkeit, die Codierung für UTF-8-Zeichen in ASCII-Zeichen zu ändern, ohne Import- / Export-Tools zu verwenden oder in eine flache Datei zu kopieren? Dh kann ich diese Konvertierung über eine Abfrage vornehmen?
  • Gibt es eine Möglichkeit, problematische Datensätze programmgesteuert über eine Abfrage zu identifizieren (problematisch als UTF-8-Zeichen definiert, die nicht über ASCII unterstützt werden)?

Danke im Voraus!

Mit sp_help N'table_name';fand ich, dass die Sortierung dieser VARCHARSpalte ist : SQL_Latin1_General_CP1_CI_AS.

Eric
quelle
Welche Sortierung verwendet diese VARCHARSpalte?
Solomon Rutzky
@SolomonRutzky Wie überprüfst du die Sortierung? Ich bin nicht sicher, was das überhaupt bedeutet
Eric
Der schnellste Weg, den ich denke, ist : sp_help N'table_name';. Schauen Sie sich die Spalte basierend auf "Name" und dann die Spalte "Kollationsname" an.
Solomon Rutzky
@SolomonRutzky Die Sortierung für dieses Feld lautet 'SQL_Latin1_General_CP1_CI_AS'
Eric

Antworten:

17

SQL Server speichert UTF-8 unter keinen Umständen. Sie erhalten entweder UTF-16 Little Endian (LE) über NVARCHAR(einschließlich NCHARund NTEXT, aber nie verwendet NTEXT) und XMLoder eine 8-Bit-Codierung basierend auf einer Codepage über VARCHAR(einschließlich CHARund TEXT, aber nie verwenden TEXT). .

Das Problem hierbei ist, dass Ihr Code dieses 0x82-Zeichen falsch übersetzt und denkt, dass es UTF-8 ist, aber nicht. Es gibt kein UTF-8 "Zeichen" mit dem Wert 0x82, weshalb Sie das "Unbekannte" / Ersatzsymbol " " erhalten. In der folgenden UTF-8-Tabelle wird angezeigt, dass für ein Einzelbyte von 0x82 kein Zeichen vorhanden ist:

UTF-8-Codierungstabelle

Wie vom OP angegeben, lautet die Sortierung der betreffenden Spalte SQL_Latin1_General_CP1_CI_AS, was bedeutet, dass für die 8-Bit-Codierung Code Page 1252 verwendet wird, bei dem es sich um Windows Latin 1 (ANSI) handelt . Wenn Sie dieses Diagramm überprüfen (scrollen Sie nach unten zum unteren Diagramm, da es die Zeichennamen enthält), ist der Wert 0x82 (suchen Sie in der Spalte " Codepunkt " nach "82") tatsächlich das einfache Anführungszeichen für niedrige 9 , das Sie in SSMS sehen. Dieses Zeichen in UTF-8 ist eine 3-Byte-Sequenz : E2 80 9A.

Dies alles bedeutet: Ihr Python-Code muss entweder die Client-Codierung für die SQL Server-Verbindung auf Code Page 1252 festlegen oder die Codierung der zurückgegebenen Zeichenfolge von Code Page 1252 auf UTF-8 ändern / konvertieren .

Wenn dies auf einer Webseite angezeigt wird, können Sie natürlich den deklarierten Zeichensatz der Seite ändern. Dies kann jedochWindows-1252 andere Zeichen auf der Seite beeinträchtigen, wenn bereits UTF-8-Zeichen vorhanden sind.

Solomon Rutzky
quelle
Schön, das ist sehr hilfreich, danke Solomon. Bitte lassen Sie mich über die Fehlübersetzung wissen. Dies ist ein ziemlich kniffliges Problem, und ich bin mir nicht einmal sicher, wo ich damit anfangen soll.
Eric
Wow, erstaunliches Detail, @Solomon! Ich bin hier gelandet und habe nach einem anderen Python + MS SQL-Problem gesucht, habe aber weiter gelesen, weil ich so viel gelernt habe. :-P
Mike Williamson
1
@ MikeWilliamson Danke, dass du dieses Kompliment geteilt hast :). Möglicherweise interessieren Sie sich auch für Folgendes: TSQL md5-Hash, der sich von C # .NET md5 (auf SO) unterscheidet, So entfernen Sie hebräische Akzentzeichen (hier auf DBA.SE) und Collations.Info . Genießen!
Solomon Rutzky
Vielen Dank! Ich vermute, dass jeder, der mit einer nicht auf Latein basierenden Sprache arbeitet, dieses Zeug weitaus besser kennt als jeder von uns, der selig in den USA / Großbritannien arbeitet. :)
Mike Williamson
1
Nur eine Anmerkung: MS SQL Server 2019 führt die native Unterstützung für UTF-8 in VARCHAR / CHAR-Datentypen ein.
Gregory Arenius