这个T-SQL何时变得不正确?或者总是拥有它?

时间:2011-05-05 11:38:27

标签: sql sql-server tsql

为什么以下(最后两个)语句返回不同的结果。我几乎100%确定他们'用'来返回相同的结果(有人回忆起过去在SQL Server 6/2000中的情况吗?)。

CREATE TABLE [dbo].[color](
    [colorid] [int] NOT NULL,
    [title] [varchar](255) NOT NULL
) ON [PRIMARY]
INSERT color SELECT 1,'Red' UNION ALL SELECT 2,'Green' UNION ALL SELECT 3,'Blue'

CREATE TABLE [dbo].[membercolor](
    [memberid] [int] NOT NULL,
    [colorid] [int] NOT NULL
) ON [PRIMARY]
INSERT membercolor SELECT 10,1 UNION ALL SELECT 10,2 UNION ALL SELECT 10,3 UNION ALL SELECT 11,1 UNION ALL SELECT 11,2 UNION ALL SELECT 12,1

SELECT * FROM color
SELECT * FROM membercolor

-- red, green & blue
SELECT * FROM color a LEFT JOIN membercolor b 
    ON a.colorid=b.colorid AND b.memberid=11

-- red, green - but why?    
SELECT * FROM color a LEFT JOIN membercolor b 
    ON a.colorid=b.colorid WHERE b.memberid IS NULL OR b.memberid=11

3 个答案:

答案 0 :(得分:3)

is null检查仅适用于colors完全没有匹配的membercolor

如果任何membercolor匹配,您最终会得到如下结果集:

color blue memberid 8
color blue memberid 9
color blue memberid 10

应用where子句过滤掉所有蓝色行:

memberid IS NULL OR b.memberid=11

如果没有membercolor匹配,则结果集如下所示:

color blue memberid NULL

where子句将允许它通过。

答案 1 :(得分:2)

将FROM子句视为处理的一个独立部分,而不是WHERE子句(从标准的角度来看,每个产品都必须假装它)。

在LEFT JOIN期间,系统将从左表中获取每一行,并尝试在右表中查找匹配项。如果有匹配项,那么它将在输出中为右表中的每个匹配行生成一行。 如果没有匹配,那么它将生成一行,右表中的所有列都设置为NULL。

在您的第一个查询中,确实会发生这种情况。但是在第二个查询中,在FROM子句处理期间,它设法生成一个与JOIN条件匹配的行:

3   Blue      10    3

因此它永远不会为右表中的那些列生成具有NULL值的行。

现在,处理WHERE子句时,您的条件会从最终结果集中排除此行。

正如其他人所说,你可能记得ANSI之前的连接语法,这可能会产生令人惊讶的结果。

答案 2 :(得分:1)

总是这样(至少从2000年开始) - 要知道原因,请查看其他声明:

SELECT * FROM color a LEFT JOIN membercolor b 
    ON a.colorid=b.colorid 

另一方面,您可能想要的是:

SELECT * FROM color a LEFT JOIN membercolor b 
    ON a.colorid=b.colorid AND b.memberid=11 WHERE b.memberid IS NULL OR b.memberid=11