Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Konvertierung von Unicode in Nicht-Unicode

Hier sind einige Dinge zu beachten:

  1. Wenn Sie genau sehen möchten, welches Zeichen dort steht, können Sie den Wert in VARBINARY umwandeln was Ihnen den hexadezimalen / binären Wert aller Zeichen in der Zeichenfolge gibt, und es gibt kein Konzept für "versteckte" Zeichen in hex:

    DECLARE @PostalCode NVARCHAR(20);
    SET @PostalCode = N'053000'+ NCHAR(0x2008); -- 0x2008 = "Punctuation Space"
    SELECT @PostalCode AS [NVarCharValue],
           CONVERT(VARCHAR(20), @PostalCode) AS [VarCharValue],
           CONVERT(VARCHAR(20), RTRIM(@PostalCode)) AS [RTrimmedVarCharValue],
           CONVERT(VARBINARY(20), @PostalCode) AS [VarBinaryValue];
    

    Rückgabe:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
    

    NVARCHAR Daten werden als UTF-16 gespeichert, das in 2-Byte-Sätzen funktioniert. Wenn wir uns die letzten 4 Hex-Ziffern ansehen, um zu sehen, was der versteckte 2-Byte-Satz ist, sehen wir "0820". Da Windows und SQL Server UTF-16 Little Endian (d. h. UTF-16LE) sind, sind die Bytes in umgekehrter Reihenfolge. Spiegeln der letzten 2 Bytes -- 08 und 20 -- wir erhalten "2008", das ist das "Interpunktions-Leerzeichen", das wir über NCHAR(0x2008) hinzugefügt haben .

    Beachten Sie außerdem, dass RTRIM hat hier überhaupt nicht geholfen.

  2. Vereinfacht gesagt können Sie die Fragezeichen einfach durch nichts ersetzen:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
    
  3. Noch wichtiger ist, dass Sie den [PostalCode] konvertieren Feld zu VARCHAR damit es diese Zeichen nicht speichert. Kein Land verwendet Buchstaben, die nicht im ASCII-Zeichensatz dargestellt werden und die für den VARCHAR-Datentyp nicht gültig sind, zumindest soweit ich darüber gelesen habe (siehe unterer Abschnitt für Referenzen). Tatsächlich ist eine ziemlich kleine Teilmenge von ASCII erlaubt, was bedeutet, dass Sie auf dem Weg hinein leicht filtern können (oder einfach dasselbe REPLACE tun wie oben gezeigt beim Einfügen oder Aktualisieren):

    ALTER TABLE [table] ALTER COLUMN [PostalCode] VARCHAR(20) [NOT]? NULL;
    

    Achten Sie darauf, den aktuellen NULL zu überprüfen / NOT NULL Einstellung für die Spalte und machen Sie sie in der ALTER-Anweisung oben gleich, sonst könnte sie geändert werden, da der Standardwert NULL ist falls nicht angegeben.

  4. Wenn Sie das Schema der Tabelle nicht ändern können und eine regelmäßige "Bereinigung" der fehlerhaften Daten durchführen müssen, können Sie Folgendes ausführen:

    ;WITH cte AS
    (
       SELECT *
       FROM   TableName
       WHERE  [PostalCode] <>
                      CONVERT(NVARCHAR(50), CONVERT(VARCHAR(50), [PostalCode]))
    )
    UPDATE cte
    SET    cte.[PostalCode] = REPLACE(CONVERT(VARCHAR(50), [PostalCode]), '?', '');
    

    Bitte beachten Sie, dass die obige Abfrage nicht effizient funktionieren soll, wenn die Tabelle Millionen von Zeilen enthält. An diesem Punkt müsste es in kleineren Sätzen über eine Schleife gehandhabt werden.

Als Referenz finden Sie hier den Wikipedia-Artikel für Postleitzahl , die derzeit besagt, dass die einzigen jemals verwendeten Zeichen sind:

Und bezüglich der maximalen Größe des Feldes, hier ist die Wikipedia Liste der Postleitzahlen