Join 带Where子句的左外连接
我对Access很有经验,在SQL Server SSMS中使用了大约12个月 我没有得到我所期望的左外连接的结果,我不知道为什么。也许我不明白什么 我有表1(左侧)和600k产品 我有150000个产品的表2(表1的子集) 当我这么做的时候Join 带Where子句的左外连接,join,outer-join,Join,Outer Join,我对Access很有经验,在SQL Server SSMS中使用了大约12个月 我没有得到我所期望的左外连接的结果,我不知道为什么。也许我不明白什么 我有表1(左侧)和600k产品 我有150000个产品的表2(表1的子集) 当我这么做的时候 SELECT [Product_Code], [Product_Desc], Store FROM [Product Range] 我有60万张唱片 当我做这样的左连接时 SELECT [Product_Code], [Product_De
SELECT [Product_Code], [Product_Desc], Store
FROM [Product Range]
我有60万张唱片
当我做这样的左连接时
SELECT [Product_Code], [Product_Desc], r.store, soh.SOH
FROM [Product Range] as r
LEFT JOIN [dbo].SOH as soh on r.[Product_Code] = soh.PRODUCT_Code
AND r.store = soh.store
WHERE soh.CalYearWeek=1512
我有50万张唱片。但是我很困惑。我认为左联接应该返回我左表中的所有记录,而不考虑其他任何内容
然后我尝试了这个(我不知道为什么我需要添加空条件)
我有55万张唱片,但还没有全部60万张
我完全糊涂了,不知道怎么了。有人能帮我吗:-)
Matt您是正确的,没有WHERE子句的基本左联接将为左表中的所有记录返回一行,其中右表的数据(如果存在)或NULL(如果不存在) 这就是你得到的,但是你添加了一个WHERE子句,它将过滤掉某些行。因此,如果你刚刚有:
SELECT [Product_Code] ,[Product_Desc] ,r.store ,soh.SOH
FROM [Product Range] as r left join [dbo].SOH as soh
on r.[Product_Code] = soh.PRODUCT_Code
and r.store = soh.store
那么您将看到返回的60万条记录。
但随后您将删除soh.CalYearWeek不是1512的10万条记录,行为:
WHERE soh.CalYearWeek=1512
加入:
or soh.CalYearWeek is null
您将添加回5万条以上的记录。所以基本上,WHERE子句在当时(连接发生后)作用于整个记录集,并过滤掉不匹配的行。在where子句中提到RIGHTTABLE.COLUMN实际上只是因为到那时,整行中的列由该完整标识符描述,而不仅仅是其列名。没有WHERE子句的基本左联接将为左表中的所有记录返回一行,其中右表的数据(如果存在)或空(如果不存在) 这就是你得到的,但是你添加了一个WHERE子句,它将过滤掉某些行。因此,如果你刚刚有:
SELECT [Product_Code] ,[Product_Desc] ,r.store ,soh.SOH
FROM [Product Range] as r left join [dbo].SOH as soh
on r.[Product_Code] = soh.PRODUCT_Code
and r.store = soh.store
那么您将看到返回的60万条记录。
但随后您将删除soh.CalYearWeek不是1512的10万条记录,行为:
WHERE soh.CalYearWeek=1512
加入:
or soh.CalYearWeek is null
您将添加回5万条以上的记录。所以基本上,WHERE子句在当时(连接发生后)作用于整个记录集,并过滤掉不匹配的行。where子句中提到RIGHTTABLE.COLUMN实际上只是因为到那时,整行中的列由该完整标识符描述,而不仅仅是它的列名。问题在于,在进行连接后执行了
where
条件,因此,soh.CalYearWeek=1512
仅对成功的联接为真-丢失的联接具有所有空值,where子句会将它们过滤掉
解决方案很简单:将条件移动到联接中:
连接上的条件是在进行连接时执行的,因此您仍将获得左侧连接,但仅限于右表中具有该特殊条件的行
在
WHERE
子句的右表上放置非空条件有效地将左连接转换为内部连接,因为只有在连接成功时,右表才能具有非空值。问题在于,在连接完成后执行WHERE
条件,因此,soh.CalYearWeek=1512
仅对成功的联接为真-丢失的联接具有所有空值,where子句会将它们过滤掉
解决方案很简单:将条件移动到联接中:
连接上的条件是在进行连接时执行的,因此您仍将获得左侧连接,但仅限于右表中具有该特殊条件的行
在
WHERE
子句的右表上放置非空条件有效地将左连接转换为内部连接,因为只有在连接成功时,右表才能具有非空值。事实上,问题不在WHERE
子句中。如果可以称之为问题的话,问题在于JOIN
本身及其行为。事实上,您可以得到正好600K行,完全没有行,少于600K行,甚至超过600K行。这取决于这些表中的数据
您应该理解将谓词放入JOIN
条件和WHERE
子句之间的区别。这有很大的区别。您还应该了解谓词如何与NULL
s一起工作
若在左表中有一行代码为“a”,而在右表中并没有代码为“a”的行,那个么将从左表中得到一行,从右表中得到空值。若在右边的表格中有一行代码为“A”,则从左边得到一行,从右边得到一行。如果左表中有N
行代码为'A',右表中有M
行代码为'A',则结果中会出现M*N
行
这里总结一下使用左联接时计算结果集中行数的公式:
COUNT=左表中没有对应行的行数+和(COUNT(code[i])*COUNT(code[i]))
,即两个表中不同匹配代码的计数的笛卡尔乘积之和
在左联接之后,您至少可以得到600K行。在year
列中,可以通过两种方式获取空值:1。右表2中的代码没有对应的行。右表中有对应的行,但列year本身为空
当您使用soh.CalYearWeek=1512进一步筛选结果集时,结果中将删除带有空值和不同值的行
举个例子:
DECLARE @t1 TABLE(Code INT)
DECLARE @t2 TABLE(Code INT, Year INT)
INSERT INTO @t1 VALUES
(1), (2), (3)
SELECT * FROM @t1 t1
JOIN @t2 t2 ON t2.Code = t1.Code
WHERE t2.Year = 1512
现在根据第二个表中的数据得出不同的结果:
--count 1
INSERT INTO @t2 VALUES
(1, 1512)
--count 0
INSERT INTO @t2 VALUES
(1, NULL)
--count 3
INSERT INTO @t2 VALUES
(1, 1512), (1, 1512), (1, 1512)
--count 6
INSERT INTO @t2 VALUES
(1, 1512), (2, 1512), (2, 1512), (3, 1512), (3, 1512), (3, 1512)
事实上,问题不在WHERE
子句中。如果你可以称之为问题,那么问题就在JOIN
its中