SQL Server 2008 Conversion VARCHAR (50) à Uniqueidentifier
-
22-08-2019 - |
Question
Je suis en train de convertir une colonne varchar (50) à un uniqueidentifier, mais cette erreur cesse d'apparaître tout le temps, et je ne sais pas pourquoi:
"Msg 8169, Level 16, State 2, Line 1 Conversion failed when converting from a character string to uniqueidentifier."
Les données dans la colonne est actuellement uniqueidentifier valide.
Quelle est la bonne façon de faire ce que je veux?
Merci
La solution
Avez-vous des colonnes contenant des chaînes vides? C'est à dire. NOT NULL, la longueur de chaîne = 0.
Ou avez-vous avec GUIDs caractères non standard? C'est à dire. non 0-9, A-F?
Nous avons quelques GUIDs non standard dans ma demande qui ont été créés avant hérité ...
EDIT:
Pour l'avenir de l'aide, ce script peut vous aider à trouver toutes les lignes qui ne sont pas valides:
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')
Toutes les lignes qui ont Guids non valides apparaissent et peuvent être trouvés par:
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'
Autres conseils
Je sais que cela a déjà répondu, mais il y a une approche un peu plus élégante. Vous pouvez utiliser le simpliste, la syntaxe exactement-one-caractère générique (c.-à-[]
) permise dans une clause de LIKE
pour tester les chiffres hexadécimaux valides (à savoir 0 - 9 et a - F). Et, à l'aide d'une clause de LIKE
avec la recherche d'un seul caractère, vous pouvez également appliquer le format d'un GUID valide / UNIQUEIDENTIFIER
d'une manière plus lisible alors la méthode de REPLACE
qui doit d'abord normaliser tous les chiffres hexadécimaux à des 0 avant de comparer au format valide .
SETUP
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);
Tests
L'exemple ci-dessous montre à l'aide de 32 ensembles de [0-9A-F]
pour chaque position hex chiffres du GUID et a les tirets (-
) dans les endroits appropriés. S'il vous plaît noter:
- la barre oblique inverse (
\
) à la fin de chaque ligne dans le motif deLIKE
est le T-SQL ligne Suite caractère et - vous devez utiliser un classement binaire pour faire en sorte que les plages de « 0-9 » et « A-F » ne correspond pas à tous les caractères qui ont des valeurs dans cette plage, mais ne sont pas spécifiquement chiffres après la virgule. Par exemple, l'indice supérieur caractère « 2 » (de
²
) n'est pas une 2 décimales, mais il a une valeur de 2 lorsqu'elle est utilisée dans un générique de gamme et en utilisant des règles de comparaison Unicode (qui sont les règles utilisées pour toutes les donnéesNVARCHAR
et mêmeVARCHAR
IF le classement est un classement Windows - nom de classement pas en commençant parSQL_
). Test ligne n ° 9 vérifie ce cas. Cependant, en faisant une comparaison binaire nécessite soit rendre le motif de gamme[0-9A-Fa-f]
ou enveloppant la colonne dans une fonction deUPPER()
. UtilisezLatin1_General_100_BIN2
sauf si vous utilisez SQL Server 2000 ou 2005, dans ce cas, vous devez utiliserLatin1_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;
Et, alors que cette question a été posée dans le contexte de SQL Server 2008, pour toute personne utilisant SQL Server 2012 ou plus récent, le TRY_CONVERT fonction permet encore plus facile:
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
*/
Sur 5000 lignes I avait un contenant un caractère non valide hex.