it-swarm.com.de

Das Konvertieren von varbinary-Daten in varchar in SQLServer führt zu unerwarteten Ergebnissen

Ich muss ein Datenkonvertierungsproblem in SQL Server 2008 beheben. Beim Speichern der Daten wurden einige Änderungen an den Anforderungen vorgenommen. Ohne viel Sorgfalt habe ich vorhandene varbinary Daten mit CONVERT(NVARCHAR(max), @bytearraydata, 1) in varchar konvertiert.

Die gleiche Konvertierung in C # erfolgt mit den Methoden Encoding.Default.GetString Und Encoding.Default.GetBytes. Encoding.Default.GetBytes(string) holt das Bytearray zurück, wie es früher war. Wenn ich jedoch versuche, das Byte-Array der Zeichenfolge, das ich mit CONVERT() konvertiert habe, zurückzugewinnen, erhalte ich ein falsches Ergebnis.

Meine Arbeit besteht darin, das als Zeichenfolge der Datenbank gespeicherte Byte-Array abzurufen, es in ein Byte-Array zu konvertieren und den Inhalt schließlich als PDF zu rendern. Daten, die den Codierungsmechanismus durchlaufen (beim Speichern und beim Abrufen), funktionieren für mich einwandfrei. Wenn ich jedoch versuche, die mit CONVERT konvertierten Daten abzurufen, kann kein PDF generiert werden.

Wie kann ich dieses Problem lösen?

Zusammenfassung:

Die Byte-Array-Spalte wurde in Zeichenfolge geändert.

Bestehende Datenkonvertierung mit dieser Funktion:

Convert(NVARCHAR(MAX), @bytearraydata, 1)

In der Anwendung erfolgt die Konvertierung des Byte-Arrays mit Encoding.Default.GetString(bytearraydata)

Sind Encoding und CONVERT nicht kompatibel?

3
user3169103

Wenn Sie Encoding.Default Das Ergebnis hängt von den lokalen Einstellungen ab:

Eine Codierung für die aktuelle ANSI-Codepage des Betriebssystems.

Die Spezifikation ist ziemlich direkt über die Gefahren der Verwendung der Standardcodierung und ruft ganz speziell die Empfehlung auf, sie nicht zu verwenden:

Verschiedene Computer können standardmäßig unterschiedliche Codierungen verwenden, und die Standardcodierung kann sich sogar auf einem einzelnen Computer ändern. Daher werden Daten, die von einem Computer auf einen anderen gestreamt oder sogar zu unterschiedlichen Zeiten auf demselben Computer abgerufen werden, möglicherweise falsch übersetzt. Darüber hinaus verwendet die von der Default-Eigenschaft zurückgegebene Codierung den Best-Fit-Fallback, um nicht unterstützte Zeichen Zeichen zuzuordnen, die von der Codepage unterstützt werden. Aus diesen beiden Gründen wird die Verwendung der Standardcodierung im Allgemeinen nicht empfohlen

Aus irgendeinem Grund erwarten Sie nun, dass die zufällige aktuelle lokale Codierung mit der Servercodierung übereinstimmt. Selbst wenn die Funktion CONVERT das tun würde, was Sie glauben, wären die Ergebnisse zufällig und unvorhersehbar, weil:

  • die lokale Codepage des Servers kann von der Client-Codepage abweichen.
  • eine Änderung der Codepage würde die persistierten Daten unlesbar machen, da sie mit einer Codierung geschrieben und dann versucht wurden, mit einer anderen gelesen zu werden.

Außerdem macht CONVERT nicht , was Sie erwarten. CONVERT wandelt ein VARBINARY mit der UCS-2-Codierung in ein NVARCHAR um, da dies die Codierung ist, die SQL Server für NVARCHAR-Daten verwendet.

Ich schlage vor, Sie nähern sich Ihrem dringenden Problem, indem Sie zuerst diesen Artikel lesen Das absolute Minimum, das jeder Softwareentwickler unbedingt über Unicode und Zeichensätze wissen muss (keine Ausreden!) . Folgen Sie mit Internationale Überlegungen für SQL Server .

1
Remus Rusanu

Die Frage enthält einige Verwirrungen, die zu unerwarteten Ergebnissen führen:

  1. Die Begriffe VARCHAR und NVARCHAR werden synonym verwendet (oder so scheint es), sind jedoch sehr unterschiedlich. NVARCHAR ist eine 16-Bit-Codierung - UTF-16 LE (Little Endian) um genau zu sein - und dies ändert sich nicht. VARCHAR ist eine 8-Bit-Codierung, und die verwendete spezifische 8-Bit-Codierung wird durch die Codepage bestimmt, die der Sortierung der Spalte zugeordnet ist (wir ignorieren VARCHAR -Daten in Zeichenfolgenliteralen und Variablen für den Moment, da es sich bei dieser Frage um Daten handelt, die in einer Tabelle gespeichert sind. Wenn Sie wissen möchten, welche Codepage einer bestimmten Sortierung zugeordnet ist, können Sie die integrierten Funktionen COLLATIONPROPERTY verwenden:

    SELECT COLLATIONPROPERTY(N'Latin1_General_100_CI_AS_SC', 'CodePage') AS [CodePage];
    -- 1252
    
  2. Bei der Konvertierung zwischen VARBINARY und entweder VARCHAR oder NVARCHAR müssen Sie darauf achten, dass Sie mit diesem Zeichenfolgendatentyp konsistent sind. Sie können nicht von VARCHAR nach VARBINARY konvertieren und dann dasselbe VARBINARY nehmen und in NVARCHAR konvertieren.

  3. Die Klasse Encoding in .NET repräsentiert eine bestimmte Codierung von Text, sei es 7-Bit, 8-Bit, 16-Bit, 32-Bit oder variabel (wie UTF-8). Um "erwartete" Ergebnisse zu erhalten, müssen Sie eine Codierung erstellen, die mit der Darstellung übereinstimmt, in die oder in Bezug auf die Darstellung byte[] Konvertiert werden muss. Zeichenfolgen in .NET sind immer UTF-16 LE (wie NVARCHAR), und darauf bezieht sich die Unicode -Codierung in .NET. Die byte[] - Darstellung einer Codierung entspricht der erstellten Codierung, die Zeichenfolgendarstellung lautet jedoch immer UTF-16 LE. Welche Codierung erstellt werden soll, hängt also davon ab, mit welcher Art von Daten Sie es zu tun haben:

    • NVARCHAR : Verwenden Sie Encoding.Unicode
    • VARCHAR : Bestimmen Sie die Codepage der Kollatierung über COLLATIONPROPERTY(N'collation_name', 'CodePage') und verwenden Sie dann diesen int -Wert in Encoding.GetEncoding(CodePageIntValue).
  4. Achten Sie bei Verwendung der integrierten Funktion CONVERT darauf, welche "Stil" -Nummer Sie verwenden. Zum Beispiel:

    SELECT CONVERT(VARBINARY(50), N'bob');
    -- 0x62006F006200
    

    Nehmen Sie nun den zurückgegebenen Wert VARBINARY und konvertieren Sie ihn zurück in NVARCHAR, wobei Sie die "Stil" -Werte 0 (Standard) und 1 (in denen Ihre Funktion CONVERT verwendet) verwenden die Frage):

    SELECT CONVERT(NVARCHAR(MAX), 0x62006F006200, 0) AS [Style_0],
           CONVERT(NVARCHAR(MAX), 0x62006F006200, 1) AS [Style_1];
    

    Kehrt zurück:

    Style_0        Style_1
    bob            0x62006F006200
    

Also, wenn die folgende Aussage aus der Frage wahr ist:

In der Anwendung erfolgt die Konvertierung des Byte-Arrays mit Encoding.Default.GetString(bytearraydata)

dann würde das bedeuten, VARCHAR anstelle von NVARCHAR und einen "Stil" -Wert von 0 (oder nichts) anstelle von 1 zu verwenden:

CONVERT(VARCHAR(MAX), 0x62006F006200)
1
Solomon Rutzky

Ich kann dieses Problem nicht replizieren. Gab es zusätzliche Schritte? Ich kann Text ohne Verlust in Binär und wieder zurück konvertieren oder umgekehrt:

DECLARE @OrigText      VARCHAR  (100) = 'There once was a bear'
DECLARE @Binary        VARBINARY(100) = CONVERT(VARBINARY(100), @OrigText)
DECLARE @RoundTripText VARCHAR  (100) = CONVERT(VARCHAR  (100), @Binary)
DECLARE @RoundTripBin  VARBINARY(100) = CONVERT(VARBINARY(100), @RoundTripText)

SELECT @OrigText, @Binary, @RoundTripText, @RoundTripBin

Ergebnisse:

  • Es war einmal ein Bär
  • 0x5468657265206F6E63652077617320612062656172
  • Es war einmal ein Bär
  • 0x5468657265206F6E63652077617320612062656172

Dies funktioniert auch mit NVARCHAR und mit CAST anstelle von CONVERT. Beachten Sie, dass ich keinen Stil für CONVERT spezifiziere. Wenn Sie eine angeben, ist mein Verständnis, dass Ihr Text eine hexadezimale Zeichenfolge sein muss. Speichern Sie das oder handelt es sich um konventionelleren Text?

0