sql >> Database >  >> RDS >> Sqlserver

Unicode naar niet-Unicode conversie

Er zijn een paar dingen om op te merken:

  1. Als je precies wilt zien welk teken er is, kun je de waarde converteren naar VARBINARY die je de hex / binaire waarde van alle karakters in de string geeft en er is geen concept van "verborgen" karakters 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];
    

    Retourneren:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
    

    NVARCHAR gegevens worden opgeslagen als UTF-16 die werkt in sets van 2 bytes. Als we naar de laatste 4 hexadecimale cijfers kijken om te zien wat de verborgen set van 2 bytes is, zien we "0820". Aangezien Windows en SQL Server UTF-16 Little Endian zijn (d.w.z. UTF-16LE), staan ​​de bytes in omgekeerde volgorde. De laatste 2 bytes omdraaien -- 08 en 20 -- we krijgen "2008", wat de "Interpunctieruimte" is die we hebben toegevoegd via NCHAR(0x2008) .

    Houd er ook rekening mee dat RTRIM hielp hier helemaal niet.

  2. Simpel gezegd kun je de vraagtekens gewoon door niets vervangen:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
    
  3. Wat nog belangrijker is, u moet de [PostalCode] . converteren veld naar VARCHAR zodat het deze tekens niet opslaat. Geen enkel land gebruikt letters die niet worden weergegeven in de ASCII-tekenset en die niet geldig zijn voor het VARCHAR-gegevenstype, tenminste voor zover ik er ooit over heb gelezen (zie het onderste gedeelte voor referenties). In feite is wat is toegestaan ​​een vrij kleine subset van ASCII, wat betekent dat je gemakkelijk kunt filteren op de weg naar binnen (of gewoon hetzelfde doet REPLACE zoals hierboven getoond bij het invoegen of bijwerken):

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

    Controleer de huidige NULL / NOT NULL instelling voor de kolom en maak het hetzelfde in de ALTER-instructie hierboven, anders kan het worden gewijzigd omdat de standaard NULL is indien niet gespecificeerd.

  4. Als u het schema van de tabel niet kunt wijzigen en periodiek de slechte gegevens moet "opschonen", kunt u het volgende uitvoeren:

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

    Houd er rekening mee dat de bovenstaande query niet bedoeld is om efficiënt te werken als de tabel miljoenen rijen heeft. Op dat moment zou het in kleinere sets via een lus moeten worden afgehandeld.

Ter referentie, hier is het wikipedia-artikel voor Postcode , waarin momenteel staat dat de enige tekens die ooit zijn gebruikt zijn:

En wat betreft de maximale grootte van het veld, hier is de Wikipedia Lijst met postcodes



  1. Hoe gebruik je een tekenreeks/kolomwaarde als mysql-datumintervalconstante (DAG, MAAND...)?

  2. waarden krijgen die niet in de mysql-tabel voorkomen

  3. Converteer tijdstempel/datumtijd van UTC naar EST Oracle SQL

  4. Tijdsverschil binnen kantooruren