SQL Server 2008将VARCHAR(50)转换为Uniqueidentifier

时间:2009-03-27 13:40:41

标签: sql-server tsql sql-server-2008 type-conversion uniqueidentifier

我正在尝试将varchar(50)列转换为uniqueidentifier,但是这个错误一直在弹出,我不知道为什么:

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

列中的数据当前是有效的uniqueidentifier。

做我想做的事的正确方法是什么?

由于

3 个答案:

答案 0 :(得分:5)

你有任何包含空字符串的列吗?即NOT 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')

任何具有无效Guids的行都会显示出来,可以通过以下方式找到:

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'

答案 1 :(得分:0)

感谢您的回复。在5000行中,我有一行包含非十六进制有效字符。

答案 2 :(得分:0)

我知道这已经得到了回答,但有一种更优雅的方法。您可以使用[]子句中允许的简单exactly-one-character wildcard语法(即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);

<强> TESTS

下面的示例显示了对GUID的每个十六进制数位置使用32组[0-9A-F],并在适当的位置使用短划线(-)。请注意:

  • \模式中每行末尾的反斜杠(LIKE)为T-SQL Line Continuation character
  • 您应该使用二进制排序规则来确保“0-9”和“A-F”的范围与具有该范围值但不是特定十进制数字的任何字符不匹配。例如,上标“2”字符(²)不是小数2,但在范围通配符中使用Unicode比较规则时,它的值为2(是用于所有NVARCHAR数据的规则,即使是VARCHAR IF ,排序规则是Windows排序规则 - 排序规则名称​​不是SQL_开头。测试行#9验证了这种情况。但是,进行二进制比较需要创建范围模式[0-9A-Fa-f]或将列包装在UPPER()函数中。除非您使用的是SQL Server 2000或2005,否则请使用Latin1_General_100_BIN2,在这种情况下,您应使用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
*/