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

Unicode til ikke-Unicode konvertering

Der er et par ting at bemærke her:

  1. Hvis du vil se præcist hvilket tegn der er, kan du konvertere værdien til VARBINARY som vil give dig den hexadecimale/binære værdi af alle tegn i strengen, og der er intet begreb om "skjulte" tegn 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];

    Returnerer:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
     

    NVARCHAR data gemmes som UTF-16, som fungerer i 2-byte sæt. Ser vi på de sidste 4 hex-cifre for at se, hvad det skjulte 2-byte sæt er, ser vi "0820". Da Windows og SQL Server er UTF-16 Little Endian (dvs. UTF-16LE), er bytes i omvendt rækkefølge. Vende de sidste 2 bytes -- 08 og 20 -- vi får "2008", som er "Punctuation Space", som vi tilføjede via NCHAR(0x2008) .

    Bemærk også, at RTRIM hjalp overhovedet ikke her.

  2. Forenklet set kan du bare erstatte spørgsmålstegnet med ingenting:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
     
  3. Endnu vigtigere bør du konvertere [PostalCode] felt til VARCHAR så den ikke gemmer disse tegn. Intet land bruger bogstaver, der ikke er repræsenteret i ASCII-tegnsættet, og som ikke er gyldige for VARCHAR-datatypen, i hvert fald så vidt jeg nogensinde har læst om (se nederste afsnit for referencer). Faktisk er det tilladte en ret lille delmængde af ASCII, hvilket betyder, at du nemt kan filtrere på vejen ind (eller bare gøre det samme REPLACE som vist ovenfor ved indsættelse eller opdatering):

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

    Sørg for at kontrollere den aktuelle NULL / NOT NULL indstilling for kolonnen og gør den til den samme i ALTER-sætningen ovenfor, ellers kan den ændres, da standarden er NULL hvis ikke angivet.

  4. Hvis du ikke kan ændre tabellens skema og har brug for at foretage en periodisk "rensning" af de dårlige data, kan du køre følgende:

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

    Vær opmærksom på, at ovenstående forespørgsel ikke er beregnet til at fungere effektivt, hvis tabellen har millioner af rækker. På det tidspunkt ville det skulle håndteres i mindre sæt via en loop.

Til reference, her er wikipedia-artiklen for Postnummer , som i øjeblikket siger, at de eneste tegn, der nogensinde er brugt, er:

Og med hensyn til feltets maksimale størrelse, her er Wikipedia Liste over postnumre



  1. MySQL heltalsfelt returneres som streng i PHP

  2. oracle hierarkisk forespørgsel startklausul fra join

  3. Laravel 4:Hvordan anvender man en WHERE-betingelse på alle forespørgsler i en veltalende klasse?

  4. Tuning:Et godt sted at starte