SQL Server 2008 en la conversión de VARCHAR (50) a Uniqueidentifier
-
22-08-2019 - |
Pregunta
Estoy tratando de convertir una (50) de la columna varchar a un uniqueidentifier, pero este error sigue apareciendo todo el tiempo, y yo no sé por qué:
"Msg 8169, Level 16, State 2, Line 1 Conversion failed when converting from a character string to uniqueidentifier."
Los datos en la columna es actualmente un uniqueidentifier válido.
¿Cuál es la forma correcta de hacer lo que quiero?
Gracias
Solución
¿Tiene alguna columnas que contienen cadenas vacías? Es decir. NO NULO, longitud de la cadena = 0.
O es que tiene alguna GUID con caracteres no estándar? Es decir. No 0-9, A-F?
Tenemos algunos GUID no estándar en mi solicitud que se crearon antes de que yo heredé ...
EDIT:
Para obtener ayuda futura, este script puede ayudar a encontrar las filas que no son válidos:
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')
Cualquier filas que tienen GUID no válidos se mostrarán, y se pueden encontrar 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'
Otros consejos
Sé que esto ya ha sido contestada, pero hay un enfoque un poco más elegante. Se puede utilizar el simplista, sintaxis exactamente-de un carácter comodín (es decir []
) permitido en una cláusula LIKE
para la prueba de dígitos hexadecimales válidos (es decir, 0 - 9 y a - F). Y, mediante el uso de una cláusula LIKE
con la búsqueda de un solo carácter también se puede hacer cumplir el formato de un válido GUID / UNIQUEIDENTIFIER
de una manera más fácil de leer a continuación el método REPLACE
que tiene para normalizar primero todos los dígitos hexadecimales a 0 de antes de comparar con el formato válido .
CONFIGURACIÓN
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);
PRUEBAS
El siguiente ejemplo muestra utilizando 32 conjuntos de [0-9A-F]
para cada posición hex dígitos del GUID y tiene la guiones (-
) en los lugares apropiados. Tenga en cuenta:
- la barra invertida (
\
) al final de cada línea en el patrónLIKE
es la T-SQL Línea carácter de continuación , y - se debe utilizar una intercalación binaria para asegurar que los rangos de "0-9" y "A-F" no coincide con cualquier carácter que tienen valores en ese rango, pero no son específicamente dígitos decimales. Por ejemplo, el carácter superíndice "2" (
²
) no es un decimal 2, pero tiene un valor de 2 cuando se utiliza en un comodín gama y usando reglas de comparación Unicode (que se utilizan las reglas para todos los datosNVARCHAR
y , inclusoVARCHAR
la colación es una intercalación de Windows - nombre de intercalación no a partir deSQL_
). Prueba fila # 9 verifica este caso. Sin embargo, haciendo una comparación binaria requiere ya sea haciendo que la[0-9A-Fa-f]
rango de patrones o envolver la columna en una funciónUPPER()
. UtiliceLatin1_General_100_BIN2
menos que esté utilizando SQL Server 2000 o 2005, en cuyo caso se debe utilizarLatin1_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;
Y, si bien esta pregunta se hizo en el contexto de SQL Server 2008, para cualquier persona que utiliza SQL Server 2012 o posterior, la TRY_CONVERT función hace aún más 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
*/
Fuera de 5000 filas que tenían una que contiene un carácter no hexadecimal válido.