Der er et par ting at bemærke her:
-
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
og20
-- vi får "2008", som er "Punctuation Space", som vi tilføjede viaNCHAR(0x2008)
.Bemærk også, at
RTRIM
hjalp overhovedet ikke her. -
Forenklet set kan du bare erstatte spørgsmålstegnet med ingenting:
SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
-
Endnu vigtigere bør du konvertere
[PostalCode]
felt tilVARCHAR
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 sammeREPLACE
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 erNULL
hvis ikke angivet. -
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