SQL Server 2008 Convertendo VARCHAR (50) para Uniqueidentifier
-
22-08-2019 - |
Pergunta
Eu estou tentando converter uma coluna varchar (50) a um uniqueidentifier, mas esse erro continua aparecendo o tempo todo, e eu não sei por que:
"Msg 8169, Level 16, State 2, Line 1 Conversion failed when converting from a character string to uniqueidentifier."
Os dados na coluna é atualmente um uniqueidentifier válido.
O que é a maneira correta de fazer o que eu quero?
Graças
Solução
Você tem colunas que contêm cadeias vazias? Ou seja, NOT NULL, comprimento da corda = 0.
Ou você tem quaisquer GUIDs com caracteres não-padrão? Ou seja, Não 0-9, A-F?
Temos alguns GUIDs não-padrão no meu aplicativo que foram criados antes eu herdei isso ...
EDIT:
Para futura ajuda, este script pode ajudar a encontrar todas as linhas que não são válidas:
SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0'), COUNT(*)
FROM TABLE
GROUP BY REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0')
Qualquer linhas que têm GUIDs inválidos vai aparecer, e pode ser encontrado por:
SELECT *, REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0')
FROM TABLE
WHERE REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(GUID, '1', '0'), '2', '0'), '3', '0'), '4', '0'), '5', '0'), '6', '0'), '7', '0'), '8', '0'), '9', '0'), 'A', '0'), 'B', '0'), 'C', '0'), 'D', '0'), 'E', '0'), 'F', '0') != '00000000-0000-0000-0000-0000000000'
Outras dicas
Eu sei que isso já foi respondida, mas não há uma abordagem um pouco mais elegante. Você pode usar o simplista, exatamente-uma-caractere curinga sintaxe (ou seja []
) permitido em uma cláusula LIKE
para testar dígitos hexadecimais válidos (ou seja, 0 - 9 e a - F). E, usando uma cláusula LIKE
com a única personagem-procurar você também pode aplicar o formato de um GUID / UNIQUEIDENTIFIER
válida de uma forma mais legível, em seguida, o método REPLACE
que tem de primeiro normalize todos os dígitos hexadecimais a 0 de antes de comparar com o formato válido .
CONFIGURAÇÃO
SET NOCOUNT ON;
IF (OBJECT_ID('tempdb.dbo.#GUIDs') IS NOT NULL)
BEGIN
DROP TABLE #GUIDs;
END;
CREATE TABLE #GUIDs (ID INT NOT NULL, TheGUID VARCHAR(50) NULL);
INSERT INTO #GUIDs (ID, TheGUID)
SELECT tmp.ID, tmp.TheGUID
FROM (
SELECT 1, 'E1A21B62-ACC4-4ACB-B284-0F0233F19EDA' -- valid
UNION ALL
SELECT 2, '50178543-11E6-40D2-87F1-9C4676DCF542' -- valid
UNION ALL
SELECT 3, '' -- invalid: empty string
UNION ALL
SELECT 4, '4EB30267-0EB4-413A-9B05-6EDDB943C7D8' -- valid
UNION ALL
SELECT 5, '4EB30267-0EB4-413A-9Z05-6EDDB943C7D8' -- invalid: has a "Z"
UNION ALL
SELECT 6, NULL -- invalid: is NULL
UNION ALL
SELECT 7, '18EAE6C5-7256-4598-AA0A-837718145001' -- valid
UNION ALL
SELECT 8, '18eae6c5-7256-4598-aa0a-837718145001' -- valid (lowercase version of #7)
UNION ALL
SELECT 9, '18EAE6C5-7²56-4598-AA0A-837718145001' -- invalid: has superscript "2"
) tmp (ID, TheGUID);
TESTES
O exemplo a seguir mostra o uso de 32 conjuntos de [0-9A-F]
para cada posição hexadecimal dígitos do GUID e tem os traços (-
) nos locais apropriados. Por favor nota:
- a barra invertida (
\
) no final de cada linha no padrãoLIKE
é o Linha T-SQL caráter Continuação , e - você deve usar um agrupamento binário para garantir que as faixas de "0-9" e "A-F" não encontrou nenhum caracteres que têm valores nesse intervalo, mas não são especificamente dígitos decimais. Por exemplo, o sobrescrito "2" caracteres (
²
) não é um decimal 2, mas tem um valor de 2 quando usado em um curinga gama e usando regras de comparação Unicode (que são as regras utilizadas para todos os dadosNVARCHAR
e , mesmoVARCHAR
IF o agrupamento é um agrupamento do Windows - nome de agrupamento não começando comSQL_
). Teste linha # 9 verifica neste caso. No entanto, fazendo uma comparação binário exige quer fazendo com que o padrão de faixa de[0-9A-Fa-f]
ou empacotar a coluna numa funçãoUPPER()
. UseLatin1_General_100_BIN2
a menos que você estiver usando SQL Server 2000 ou 2005, caso em que você deve usarLatin1_General_BIN
.
SELECT ID, TheGUID, CONVERT(UNIQUEIDENTIFIER, TheGUID) AS [Converted]
FROM #GUIDs
WHERE UPPER(TheGUID) COLLATE Latin1_General_100_BIN2 LIKE
'[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]\
[0-9A-F]';
SELECT ID, TheGUID AS [BAD]
FROM #GUIDs
WHERE UPPER(TheGUID) COLLATE Latin1_General_100_BIN2 NOT LIKE
'[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F]-\
[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]\
[0-9A-F]'
OR TheGUID IS NULL;
E, enquanto isso pergunta foi feita no contexto do SQL Server 2008, para qualquer um usando o SQL Server 2012 ou mais recente, a TRY_CONVERT função torna isso ainda mais fácil:
SELECT tmp.ID, tmp.TheGUID AS [BAD]
FROM #GUIDs tmp
WHERE TRY_CONVERT(UNIQUEIDENTIFIER, tmp.[TheGUID]) IS NULL;
/*
ID BAD
3
5 4EB30267-0EB4-413A-9Z05-6EDDB943C7D8
6 (NULL)
9 18EAE6C5-7²56-4598-AA0A-837718145001
*/
Fora de 5000 linhas eu tinha um contendo um caractere não hex-válido.