SQL Server 2008 Преобразование VARCHAR (50) в уникальный идентификатор - PullRequest
3 голосов
/ 27 марта 2009

Я пытаюсь преобразовать столбец varchar (50) в uniqueidentifier, но эта ошибка постоянно появляется, и я не знаю почему:

"Msg 8169, Level 16, State 2, Line 1 Conversion failed when converting from a character string to uniqueidentifier."

Данные в столбце в настоящее время являются действительными уникальными идентификаторами.

Как правильно делать то, что я хочу?

Спасибо

Ответы [ 3 ]

5 голосов
/ 27 марта 2009

Есть ли у вас столбцы, содержащие пустые строки? То есть NOT NULL, длина строки = 0.

Или у вас есть GUID с нестандартными символами? То есть не 0-9, A-F?

В моем приложении есть несколько нестандартных идентификаторов GUID, которые были созданы до того, как я его унаследовал ...

EDIT:

Для справки в будущем этот скрипт может помочь вам найти любые недопустимые строки:

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'
0 голосов
/ 15 апреля 2012

Я знаю, что на это уже ответили, но есть немного более элегантный подход. Вы можете использовать упрощенный синтаксис , состоящий только из одного символа, (т. Е. []), разрешенный в предложении LIKE, для проверки допустимых шестнадцатеричных цифр (то есть 0 - 9 и A - F). И, используя предложение LIKE с односимвольным поиском, вы также можете применять формат действительного GUID / UNIQUEIDENTIFIER более читабельным способом, чем метод REPLACE, который должен сначала нормализовать все шестнадцатеричные цифры до 0 перед сравнением с действительным форматом.

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);

ИСПЫТАНИЯ

В приведенном ниже примере показано использование 32 наборов [0-9A-F] для каждой шестнадцатеричной позиции GUID и тире (-) в соответствующих местах. Обратите внимание:

  • Обратная косая черта (\) в конце каждой строки в шаблоне LIKE представляет собой Символ продолжения строки T-SQL и
  • Вы должны использовать двоичное сопоставление, чтобы гарантировать, что диапазоны "0-9" и "A-F" не соответствуют никаким символам, которые имеют значения в этом диапазоне, но не являются конкретно десятичными цифрами. Например, верхний индекс «2» (²) не является десятичным 2, но он имеет значение 2 при использовании в подстановочном знаке диапазона и с использованием правил сравнения Unicode (которые являются правилами используется для всех NVARCHAR данных и , даже VARCHAR IF , сопоставление является сопоставлением 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 или новее, функция TRY_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
*/
0 голосов
/ 27 марта 2009

Из 5000 строк у меня была одна, содержащая недопустимый шестнадцатеричный символ.

...