sql >> Databasteknik >  >> RDS >> Sqlserver

Unicode till icke-Unicode-konvertering

Det finns några saker att notera här:

  1. Om du vill se exakt vilket tecken som finns där kan du konvertera värdet till VARBINARY som ger dig det hexadecimala/binära värdet för alla tecken i strängen och det finns inget koncept med "dolda" tecken i 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];
    

    Returnerar:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
    

    NVARCHAR data lagras som UTF-16 som fungerar i 2-byte set. När vi tittar på de sista 4 hexadecimala siffrorna för att se vad den dolda 2-byte uppsättningen är, ser vi "0820". Eftersom Windows och SQL Server är UTF-16 Little Endian (dvs UTF-16LE), är byten i omvänd ordning. Vänd de sista 2 byten -- 08 och 20 -- vi får "2008", vilket är "Punctuation Space" som vi lade till via NCHAR(0x2008) .

    Observera också att RTRIM hjälpte inte alls här.

  2. Förenklat kan du bara ersätta frågetecknen med ingenting:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
    
  3. Ännu viktigare är att du bör konvertera [PostalCode] till VARCHAR så att den inte lagrar dessa tecken. Inget land använder bokstäver som inte är representerade i ASCII-teckenuppsättningen och som inte är giltiga för VARCHAR-datatypen, åtminstone så långt jag någonsin har läst om (se det nedersta avsnittet för referenser). Det som är tillåtet är faktiskt en ganska liten delmängd av ASCII, vilket innebär att du enkelt kan filtrera på vägen in (eller bara göra samma REPLACE som visas ovan när du infogar eller uppdaterar):

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

    Var noga med att kontrollera den aktuella NULL / NOT NULL inställningen för kolumnen och gör den till samma i ALTER-satsen ovan, annars kan den ändras eftersom standardinställningen är NULL om inte specificerat.

  4. Om du inte kan ändra tabellens schema och behöver göra en periodisk "rensning" av dålig data, kan du köra följande:

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

    Tänk på att frågan ovan inte är avsedd att fungera effektivt om tabellen har miljontals rader. Då skulle det behöva hanteras i mindre uppsättningar via en loop.

För referens, här är wikipedia-artikeln för Postnummer , som för närvarande anger att de enda tecken som någonsin använts är:

Och angående den maximala storleken på fältet, här är Wikipedias listan över postnummer



  1. JDBC, Elasticsearch och Postgresql Json datatyp

  2. Hur man säkerhetskopierar eller skapar en ny tabell från befintlig SQL Server-tabell i SQL Server - SQL Server / TSQL Tutorial Del 105

  3. Hur skapar jag en användare i SQL-Server som bara har tillgång till en tabell och bara kan infoga rader

  4. Hur man identifierar ett språk i utf-8-kolumnen i MySQL