Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Conversione da Unicode a Non Unicode

Ci sono alcune cose da notare qui:

  1. Se vuoi vedere esattamente quale carattere è presente, puoi convertire il valore in VARBINARY che ti darà il valore esadecimale/binario di tutti i caratteri nella stringa e non esiste il concetto di caratteri "nascosti" in esadecimale:

    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];
    

    Resi:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
    

    NVARCHAR i dati vengono archiviati come UTF-16 che funziona in set da 2 byte. Osservando le ultime 4 cifre esadecimali per vedere qual è il set di 2 byte nascosto, vediamo "0820". Poiché Windows e SQL Server sono UTF-16 Little Endian (ovvero UTF-16LE), i byte sono in ordine inverso. Capovolgere gli ultimi 2 byte -- 08 e 20 -- otteniamo "2008", che è lo "spazio di punteggiatura" che abbiamo aggiunto tramite NCHAR(0x2008) .

    Inoltre, tieni presente che RTRIM non ha aiutato affatto qui.

  2. Semplificando, puoi semplicemente sostituire i punti interrogativi con niente:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
    
  3. Ancora più importante, dovresti convertire il [PostalCode] campo a VARCHAR in modo che non memorizzi questi caratteri. Nessun paese utilizza lettere che non sono rappresentate nel set di caratteri ASCII e che non sono valide per il tipo di dati VARCHAR, almeno per quanto ho letto (vedere la sezione in basso per i riferimenti). In effetti, ciò che è consentito è un sottoinsieme piuttosto piccolo di ASCII, il che significa che puoi facilmente filtrare durante il percorso (o semplicemente fare lo stesso REPLACE come mostrato sopra durante l'inserimento o l'aggiornamento):

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

    Assicurati di controllare l'attuale NULL / NOT NULL impostazione per la colonna e rendila uguale nell'istruzione ALTER sopra, altrimenti potrebbe essere modificata poiché l'impostazione predefinita è NULL se non specificato.

  4. Se non puoi modificare lo schema della tabella e devi eseguire una "pulizia" periodica dei dati non validi, puoi eseguire quanto segue:

    ;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]), '?', '');
    

    Tieni presente che la query precedente non è pensata per funzionare in modo efficiente se la tabella ha milioni di righe. A quel punto dovrebbe essere gestito in set più piccoli tramite un ciclo.

Per riferimento, ecco l'articolo di Wikipedia per Codice postale , che attualmente afferma che gli unici caratteri mai utilizzati sono:

E per quanto riguarda la dimensione massima del campo, ecco l'Elenco dei codici postali di Wikipedia