Há algumas coisas a serem observadas aqui:
-
Se você quiser ver exatamente qual caractere está lá, você pode converter o valor paraVARBINARY
que lhe dará o valor hexadecimal / binário de todos os caracteres na string e não há conceito de caracteres "ocultos" em hexadecimal:
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];
Devoluções:
NVarCharValue VarCharValue RTrimmedVarCharValue VarBinaryValue 053000 053000? 053000? 0x3000350033003000300030000820
NVARCHAR
os dados são armazenados como UTF-16 que funciona em conjuntos de 2 bytes. Olhando para os últimos 4 dígitos hexadecimais para ver qual é o conjunto oculto de 2 bytes, vemos "0820". Como o Windows e o SQL Server são UTF-16 Little Endian (ou seja, UTF-16LE), os bytes estão na ordem inversa. Invertendo os 2 bytes finais --08
e20
-- obtemos "2008", que é o "Espaço de pontuação" que adicionamos viaNCHAR(0x2008)
.
Além disso, observe queRTRIM
não ajudou em nada aqui.
-
De forma simplista, você pode simplesmente substituir os pontos de interrogação por nada:
SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
-
Mais importante, você deve converter o[PostalCode]
campo paraVARCHAR
para que não armazene esses caracteres. Nenhum país usa letras que não são representadas no conjunto de caracteres ASCII e que não são válidas para o tipo de dados VARCHAR, pelo menos até onde eu já li (consulte a seção inferior para referências). Na verdade, o que é permitido é um subconjunto bastante pequeno de ASCII, o que significa que você pode filtrar facilmente no caminho (ou apenas fazer o mesmoREPLACE
como mostrado acima ao inserir ou atualizar):
ALTER TABLE [table] ALTER COLUMN [PostalCode] VARCHAR(20) [NOT]? NULL;
Certifique-se de verificar oNULL
atual /NOT NULL
configuração para a coluna e torná-lo o mesmo na instrução ALTER acima, caso contrário, ele pode ser alterado, pois o padrão éNULL
se não for especificado.
-
Se você não puder alterar o esquema da tabela e precisar fazer uma "limpeza" periódica dos dados ruins, poderá executar o seguinte:
;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]), '?', '');
Lembre-se de que a consulta acima não deve funcionar de forma eficiente se a tabela tiver milhões de linhas. Nesse ponto, precisaria ser tratado em conjuntos menores por meio de um loop.
Para referência, aqui está o artigo da wikipedia para Código postal , que atualmente afirma que os únicos caracteres já usados são:
E em relação ao tamanho máximo do campo, aqui está a Lista de códigos postais da Wikipedia