[英]SQL Server : join on uniqueidentifier
I have two tables Backup
and Requests
. 我有两个表
Backup
和Requests
。
Below is the script for both the tables 以下是两个表的脚本
Backup 后备
CREATE TABLE UserBackup(
FileName varchar(70) NOT NULL,
)
File name is represented by a guid. 文件名由GUID表示。 Sometimes there is some additional information related to the file.
有时还有一些与文件有关的其他信息。 Hence we have entries like guid_ADD entried in table.
因此,我们在表中输入了类似guid_ADD的条目。
Requests 要求
CREATE TABLE Requests(
RequestId UNIQUEIDENTIFIER NOT NULL,
Status int Not null
)
Here are some sample rows : 以下是一些示例行:
UserBackup table: UserBackup表:
FileName
15b993cc-e8be-405d-bb9f-0c58b66dcdfe
4cffe724-3f68-4710-b785-30afde5d52f8
4cffe724-3f68-4710-b785-30afde5d52f8_Add
7ad22838-ddee-4043-8d1f-6656d2953545
Requests table: 请求表:
RequestId Status
15b993cc-e8be-405d-bb9f-0c58b66dcdfe 1
4cffe724-3f68-4710-b785-30afde5d52f8 1
7ad22838-ddee-4043-8d1f-6656d2953545 2
What I need is to return all the rows from userbackup table whose name (the guid) is matches RequestId
in the Requests
table and the status is 1. So here is the query I wrote 我需要从userbackup表中返回所有行,该表的名称(GUID)与
Requests
表中的RequestId
匹配,并且状态为1。所以这是我编写的查询
Select *
from UserBackup
inner join Requests on UserBackup.FileName = Requests.RequestId
where Requests.Status = 1
And this works fine. 这很好。 It returns me the following result
它给我以下结果
FileName RequestId Status
15b993cc-e8be-405d-bb9f-0c58b66dcdfe 15b993cc-e8be-405d-bb9f-0c58b66dcdfe 1
4cffe724-3f68-4710-b785-30afde5d52f8 4cffe724-3f68-4710-b785-30afde5d52f8 1
4cffe724-3f68-4710-b785-30afde5d52f8_Add 4cffe724-3f68-4710-b785-30afde5d52f8 1
This is exactly what I want. 这正是我想要的。 But what I don't understand is how it is working.
但是我不明白它是如何工作的。 If you notice the result is returning
4cffe724-3f68-4710-b785-30afde5d52f8_Add
row as well. 如果您注意到结果也返回
4cffe724-3f68-4710-b785-30afde5d52f8_Add
行。 The inner join is on varchar
and uniqueidentifier
, and this join instead of working like "Equals to" comparison works like "contains" comparison. 内部
uniqueidentifier
位于varchar
和uniqueidentifier
,该uniqueidentifier
而不是像“等于”比较那样工作,而像“包含”比较那样工作。 I want to know how this works so that I can be sure to use this code without any unexpected scenarios. 我想知道它是如何工作的,以便可以确保在没有任何意外情况的情况下使用此代码。
The values on both sides of a comparison have to be of the same data type. 比较两侧的值必须是相同的数据类型。 There's no such thing as, say, comparing a
uniqueidentifier
and a varchar
. 例如,没有比对
uniqueidentifier
和varchar
比较。
uniqueidentifier
has a higher precedence than varchar
so the varchar
s will be converted to uniqueidentifier
s before the comparison occurs. uniqueidentifier
的优先级高于varchar
因此在进行比较之前, varchar
将被转换为uniqueidentifier
。
Unfortunately, you get no error or warning if the string contains more characters than are needed: 不幸的是,如果该字符串包含的字符数超过所需数量,则不会出现任何错误或警告:
select CONVERT(uniqueidentifier,'4cffe724-3f68-4710-b785-30afde5d52f8_Add')
Result: 结果:
4CFFE724-3F68-4710-B785-30AFDE5D52F8
If you want to force the comparison to occur between strings, you'll have to perform an explicit conversion: 如果要强制在字符串之间进行比较,则必须执行显式转换:
Select *
from UserBackup
inner join Requests
on UserBackup.FileName = CONVERT(varchar(70),Requests.RequestId)
where Requests.Status = 1
When you compare two columns of different data types SQL Server will attempt to do implicit conversion on lower precedence. 当您比较不同数据类型的两列时,SQL Server将尝试以较低的优先级进行隐式转换。
The following comes from MSDN docs on uniqueidentifier
以下是来自
uniqueidentifier
MSDN文档
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.
因为uniqueidentifier类型限制为36个字符,所以超过该长度的字符将被截断。
DECLARE @ID nvarchar(max) = N'0E984725-C51C-4BF4-9960-E1C80E27ABA0wrong';
SELECT @ID, CONVERT(uniqueidentifier, @ID) AS TruncatedValue;
http://msdn.microsoft.com/en-us/library/ms187942.aspx http://msdn.microsoft.com/en-us/library/ms187942.aspx
Documentation is clear that data is truncated 文档清楚数据被截断
When ever you are unsure about your join operation you can verify Actual Execution Plan
. 每当您不确定联接操作时,都可以验证“
Actual Execution Plan
。
Here is test sample that you can run inside SSMS or SQL Sentry Plan Explorer 这是可以在SSMS或SQL Sentry Plan Explorer中运行的测试示例
DECLARE @userbackup TABLE ( _FILENAME VARCHAR(70) )
INSERT INTO @userbackup
VALUES ( '15b993cc-e8be-405d-bb9f-0c58b66dcdfe' ),
( '4cffe724-3f68-4710-b785-30afde5d52f8' ),
( '4cffe724-3f68-4710-b785-30afde5d52f8_Add' )
, ( '7ad22838-ddee-4043-8d1f-6656d2953545' )
DECLARE @Requests TABLE
(
requestID UNIQUEIDENTIFIER
,_Status INT
)
INSERT INTO @Requests
VALUES ( '15b993cc-e8be-405d-bb9f-0c58b66dcdfe', 1 )
, ( '4cffe724-3f68-4710-b785-30afde5d52f8', 1 )
, ( '7ad22838-ddee-4043-8d1f-6656d2953545', 2 )
SELECT *
FROM @userbackup u
JOIN @Requests r
ON u.[_FILENAME] = r.requestID
WHERE r.[_Status] = 1
Instead of regular join
operation SQL Server is doing HASH MATCH
with EXPR 1006
in SSMS it is hard to see what is doing but if you open XML file you will find this 而不是常规
join
运行SQL Server正在做HASH MATCH
与EXPR 1006
SSMS中是很难看到什么做什么,但如果你打开XML文件,你会发现这个
<ColumnReference Column="Expr1006" />
<ScalarOperator ScalarString="CONVERT_IMPLICIT(uniqueidentifier,@userbackup.[_FILENAME] as [u].[_FILENAME],0)">
When ever in doubt check execution plan and always make sure to match data types when comparing. 如有疑问,请检查执行计划,并在比较时始终确保匹配数据类型。
This is great blog Data Mismatch on WHERE Clause might Cause Serious Performance Problems from Microsoft engineer on exact problem. 这是很棒的博客,WHERE子句上的数据不匹配可能会导致 Microsoft工程师针对确切问题产生严重的性能问题。
What is happening here is the FileName is being converted from varchar to a UniqueIdentifier, and during that process it ignores anything after the first 36 characters. 这里发生的是FileName正在从varchar转换为UniqueIdentifier,并且在此过程中,它将忽略前36个字符之后的任何内容。
You can see it in action here 您可以在这里看到它的运行情况
Select convert(uniqueidentifier, UserBackup.FileName), FileName
from UserBackup
It works, but to reduce confusion for the next person to come along, you might want to store the RequestId associated with the UserBackup as a GUID in the UserBackup table and join on that. 它可以工作,但是为了减少下一个人的困惑,您可能希望将与UserBackup关联的RequestId作为GUID存储在UserBackup表中并加入。
At the very least put a comment in ;) 至少在;)中发表评论;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.