首页 > 解决方案 > 带有错误 GUID 的 Transact-SQL Select 语句结果

问题描述

我们有一个带有 GUID 主键的表。当我搜索一个特定的键时,我可以使用:

SELECT * FROM products WHERE productID='34594289-16B9-4EEF-9A1E-B35066531DE6'
SELECT * FROM products WHERE productID LIKE '34594289-16B9-4EEF-9A1E-B35066531DE6'

结果(两者):

product_ID                           Prd_Model
------------------------------------ --------------------------------------------------
34594289-16B9-4EEF-9A1E-B35066531DE6 LW-100

(1 row affected)

我们有一个客户使用我们的 ID,但添加了更多文本以在他们自己的系统中创建某种复合字段。他们向我发送了其中一个值进行查找,我得到了意想不到的结果。我打算修剪后缀但忘记了,所以我运行了这个:

SELECT * FROM products WHERE productID='34594289-16B9-4EEF-9A1E-B35066531DE6_GBR_USD'

当我运行它时,我意外地得到了相同的结果:

product_ID                           Prd_Model
------------------------------------ --------------------------------------------------
34594289-16B9-4EEF-9A1E-B35066531DE6 LW-062

(1 row affected)

现在,如果我在搜索时从 GUID 末尾修剪一个值,我什么也得不到(GUID 短 1 位):

SELECT * FROM products WHERE productID='34594289-16B9-4EEF-9A1E-B35066531DE'

结果:

product_ID                           Prd_Model
------------------------------------ --------------------------------------------------  

(0 rows affected)

当使用 LIKE 命令而不是 '=' 并且如果我将后缀添加到末尾时,该语句将返回零结果。这是我所期望的。

那么为什么在语句中使用'='时,末尾添加后缀的较长字符串会返回结果?它显然忽略了 36 个字符的 GUID 长度之外的任何内容,但我不知道为什么。

标签: sqlsql-servertsqlsql-server-2016

解决方案


这种行为记录在案

转换 uniqueidentifier 数据

为了从字符表达式转换的目的,uniqueidentifier 类型被视为字符类型,因此受制于转换为字符类型的截断规则。也就是说,当字符表达式转换为不同大小的字符数据类型时,对于新数据类型来说太长的值将被截断。请参阅示例部分。

因此,字符串值在被隐式转换(由于数据类型优先级)为 a时'34594289-16B9-4EEF-9A1E-B35066531DE6_GBR_USD'被截断,并且不出所料地等于自身,因此返回该行。'34594289-16B9-4EEF-9A1E-B35066531DE6'uniqueidentifier'34594289-16B9-4EEF-9A1E-B35066531DE6'

文档确实举了一个例子:

以下示例演示了当值对于要转换的数据类型而言太长时截断数据。因为 uniqueidentifier 类型限制为 36 个字符,所以超过该长度的字符将被截断。

DECLARE @ID NVARCHAR(max) = N'0E984725-C51C-4BF4-9960-E1C80E27ABA0wrong';  
SELECT @ID, CONVERT(uniqueidentifier, @ID) AS TruncatedValue;  

这是结果集。

String                                       TruncatedValue  
-------------------------------------------- ------------------------------------  
0E984725-C51C-4BF4-9960-E1C80E27ABA0wrong    0E984725-C51C-4BF4-9960-E1C80E27ABA0  

但是,我觉得你说下面的语句不返回任何行很奇怪:

SELECT * 
FROM products
WHERE productID='34594289-16B9-4EEF-9A1E-B35066531DE'

虽然是真的,但它不会返回行,它也会出错:

从字符串转换为唯一标识符时转换失败。

它并不意味着您的专栏不是一个事实,这意味着uniqueidentifier您的第一个陈述不正确;因为较长的字符串不会被截断。这意味着问题中的其中一个陈述可能是错误的;要么你的列a uniqueidentifier,因此你得到结果,但在后者中得到一个错误,或者它不是,两个语句都不会返回结果集。正如您在此演示中看到的:

CREATE TABLE dbo.YourTable (UID uniqueidentifier, String varchar(36));

INSERT INTO dbo.YourTable (UID,String)
VALUES('34594289-16B9-4EEF-9A1E-B35066531DE6','34594289-16B9-4EEF-9A1E-B35066531DE6');
GO
--Returns data
SELECT *
FROM dbo.YourTable
WHERE UID = '34594289-16B9-4EEF-9A1E-B35066531DE6_GBR_USD'
GO
--Errors
SELECT *
FROM dbo.YourTable
WHERE UID = '34594289-16B9-4EEF-9A1E-B35066531DE';
GO
--Returns no data
SELECT *
FROM dbo.YourTable
WHERE String = '34594289-16B9-4EEF-9A1E-B35066531DE6_GBR_USD'
GO
--Returns no data
SELECT *
FROM dbo.YourTable
WHERE String = '34594289-16B9-4EEF-9A1E-B35066531DE'

GO
DROP TABLE dbo.YourTable;

db<>小提琴


推荐阅读