为什么 SQL 服务器给我错误的输出?
Why is SQL Server giving me wrong output?
无意中我注意到 SSMS 中有一个类似 bug 的行为。我正在使用以下查询从名为 table 的候选人查询。
select CandidateId, CandidateName from Candidate
where CandidateId='73415005-77C6-4D4B-9947-02D6B148E03F2'
我正在复制粘贴唯一标识符 CandidateId,但不知何故我在最后添加了两 (2) 个。实际上,我要查询的候选人 ID 是“73415005-77C6-4D4B-9947-02D6B148E03F
”,并且没有候选人的候选人 ID 73415005-77C6-4D4B-9947-02D6B148E03F2
(我想这甚至不是 GUID)
但是,我还是得到了结果。
在查询和结果中可以看到,CandidateId 是不同的。为什么会这样?有没有人解释一下。
因为您的列 CandidateId 是 GUID 类型,所以条件的右侧(字符串)部分被转换为 uniqueidentifier 数据类型并被截断。您可以在执行计划中看到这一点。在您的索引 seek/scan 运算符中将有一个标量运算符(CONVERT_IMPLICIT(uniqueidentifier,[@1],0))。
那是因为您的执行计划中可能有一个 convert_implicit 并且 SQL 将 '73415005-77C6-4D4B-9947-02D6B148E03F2' 转换为一个 guid。
顶层描述是字符串正在转换为唯一标识符,因此忽略最后一位。
此逻辑已记录在案。首先,唯一标识符的运算符优先级略高于字符串。 documentation的相关部分:
- uniqueidentifier
- nvarchar (including nvarchar(max) )
- nchar
- varchar (including varchar(max) )
- char
这就是转换为 uniqueidentifier
而不是字符串的原因。
其次,这是 SQL 服务器执行 "silent conversion" 的情况。也就是说,它会转换前 36 个字符,并且不会为较长的字符串生成错误。这也是documented:
The following example demonstrates the truncation of data when the
value is too long for the data type being converted to. Because the
uniqueidentifier type is limited to 36 characters, the characters that
exceed that length are truncated.
因此,您看到的行为不是错误。它是记录在案的行为,结合了记录在案的 SQL 服务器功能的两个不同方面。
SQL 当值对于要转换成的数据类型来说太长时截断数据。
由于您尝试将 uniqueidentifier 字段与文本变量进行比较,SQL 将其转换为 uniqueidentifier。这不是错误。
例如:
select Cast('73415005-77C6-4D4B-9947-02D6B148E03F2' 作为唯一标识符)
结果:
73415005-77C6-4D4B-9947-02D6B148E03F
无意中我注意到 SSMS 中有一个类似 bug 的行为。我正在使用以下查询从名为 table 的候选人查询。
select CandidateId, CandidateName from Candidate
where CandidateId='73415005-77C6-4D4B-9947-02D6B148E03F2'
我正在复制粘贴唯一标识符 CandidateId,但不知何故我在最后添加了两 (2) 个。实际上,我要查询的候选人 ID 是“73415005-77C6-4D4B-9947-02D6B148E03F
”,并且没有候选人的候选人 ID 73415005-77C6-4D4B-9947-02D6B148E03F2
(我想这甚至不是 GUID)
但是,我还是得到了结果。
在查询和结果中可以看到,CandidateId 是不同的。为什么会这样?有没有人解释一下。
因为您的列 CandidateId 是 GUID 类型,所以条件的右侧(字符串)部分被转换为 uniqueidentifier 数据类型并被截断。您可以在执行计划中看到这一点。在您的索引 seek/scan 运算符中将有一个标量运算符(CONVERT_IMPLICIT(uniqueidentifier,[@1],0))。
那是因为您的执行计划中可能有一个 convert_implicit 并且 SQL 将 '73415005-77C6-4D4B-9947-02D6B148E03F2' 转换为一个 guid。
顶层描述是字符串正在转换为唯一标识符,因此忽略最后一位。
此逻辑已记录在案。首先,唯一标识符的运算符优先级略高于字符串。 documentation的相关部分:
- uniqueidentifier
- nvarchar (including nvarchar(max) )
- nchar
- varchar (including varchar(max) )
- char
这就是转换为 uniqueidentifier
而不是字符串的原因。
其次,这是 SQL 服务器执行 "silent conversion" 的情况。也就是说,它会转换前 36 个字符,并且不会为较长的字符串生成错误。这也是documented:
The following example demonstrates the truncation of data when the value is too long for the data type being converted to. Because the uniqueidentifier type is limited to 36 characters, the characters that exceed that length are truncated.
因此,您看到的行为不是错误。它是记录在案的行为,结合了记录在案的 SQL 服务器功能的两个不同方面。
SQL 当值对于要转换成的数据类型来说太长时截断数据。 由于您尝试将 uniqueidentifier 字段与文本变量进行比较,SQL 将其转换为 uniqueidentifier。这不是错误。
例如: select Cast('73415005-77C6-4D4B-9947-02D6B148E03F2' 作为唯一标识符)
结果:
73415005-77C6-4D4B-9947-02D6B148E03F