Er zijn een paar dingen om op te merken:
-
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
en20
-- we krijgen "2008", wat de "Interpunctieruimte" is die we hebben toegevoegd viaNCHAR(0x2008)
.Houd er ook rekening mee dat
RTRIM
hielp hier helemaal niet. -
Simpel gezegd kun je de vraagtekens gewoon door niets vervangen:
SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
-
Wat nog belangrijker is, u moet de
[PostalCode]
. converteren veld naarVARCHAR
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 doetREPLACE
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 standaardNULL
is indien niet gespecificeerd. -
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