SQL Server 2008 Преобразование VARCHAR(50) в уникальный идентификатор
-
22-08-2019 - |
Вопрос
Я пытаюсь преобразовать столбец varchar(50) в уникальный идентификатор, но эта ошибка постоянно появляется, и я не знаю, почему:
"Msg 8169, Level 16, State 2, Line 1 Conversion failed when converting from a character string to uniqueidentifier."
Данные в столбце в настоящее время являются допустимым уникальным идентификатором.
Как правильно делать то, что я хочу?
Спасибо
Решение
Есть ли у вас столбцы, содержащие пустые строки?Т.е.НЕ NULL, длина строки = 0.
Или у вас есть GUID с нестандартными символами?Т.е.не 0-9, A-F?
В моем приложении есть несколько нестандартных GUID, которые были созданы до того, как я его унаследовал...
РЕДАКТИРОВАТЬ:
В будущем этот сценарий поможет вам найти недопустимые строки:
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')
Любые строки с недопустимыми идентификаторами будут отображаться, и их можно найти следующим образом:
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'
Другие советы
Я знаю, что на этот вопрос уже был дан ответ, но есть немного более элегантный подход.Вы можете использовать упрощенный подход, подстановочный знак, состоящий ровно из одного символа синтаксис (т. []
) разрешено в LIKE
предложение для проверки допустимых шестнадцатеричных цифр (т. е.0–9 и A–F).И, используя LIKE
с помощью односимвольного поиска вы также можете обеспечить соблюдение формата действительного GUID/ UNIQUEIDENTIFIER
более читабельным образом, чем REPLACE
метод, который должен сначала нормализовать все шестнадцатеричные цифры до 0, прежде чем сравнивать их с допустимым форматом.
НАСТРАИВАТЬ
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);
ИСПЫТАНИЯ
В примере ниже показано использование 32 наборов [0-9A-F]
для каждой шестнадцатеричной позиции GUID и имеет тире (-
) в соответствующих местах.Пожалуйста, обрати внимание:
- обратная косая черта (
\
) в конце каждой строки вLIKE
образец - это Символ продолжения строки T-SQL, и - вам следует использовать двоичную сортировку, чтобы гарантировать, что диапазоны «0–9» и «AF» не соответствуют никаким символам, значения которых находятся в этом диапазоне, но не являются десятичными цифрами.Например, верхний индекс «2» (
²
) не является десятичной цифрой 2, но имеет значение 2 при использовании в подстановочном знаке диапазона. и используя правила сравнения Unicode (которые являются правилами, используемыми для всехNVARCHAR
данные и дажеVARCHAR
ЕСЛИ параметры сортировки являются параметрами сортировки Windows — имя параметра сортировки нет начиная сSQL_
).Тестовая строка №9 подтверждает этот случай.Однако выполнение двоичного сравнения требует либо создания шаблона диапазона[0-9A-Fa-f]
или обертывание столбца вUPPER()
функция.ИспользоватьLatin1_General_100_BIN2
если вы не используете SQL Server 2000 или 2005, в этом случае вам следует использоватьLatin1_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;
И хотя этот вопрос был задан в контексте SQL Server 2008, для всех, кто использует SQL Server 2012 или новее, ПОПРОБУЙТЕ_CONVERT функция делает это еще проще:
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
*/
Из 5000 строк у меня была одна, содержащая недопустимый шестнадцатеричный символ.