WHERE子句中的IS NOT NULL和ISNULL(str,NULL)

时间:2011-09-14 19:24:52

标签: sql sql-server isnull

我有三张桌子(这里简化):

recipients: recipientId, isGroup
users: userId, first name, last name
groups: groupid, groupname

如果收件人是用户,我想要检索名字/姓氏;如果收件人是组,我想要检查组名。收件人可能既不是(也就是被删除/不再存在的组),所以在这种情况下我想什么都不返回。

所以这就是我所做的:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL or g.groupname IS NOT NULL

上述查询未返回预期结果。我收到了回复:

adam, smith, null, null
yolanda, smith, null, null
null, null, members, 1
null, null, null, 1

最后一行是意外的,因为显然没有组名(g.groupname为NULL)且r.IsGroup = 1。

当我这样做时:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL

我得到了预期的结果:

adam, smith, null, null
yolanda, smith, null, null

当我这样做时:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where g.groupname IS NOT NULL

我得到了预期的结果:

null, null, members, 1

只有当我将两个where子句与OR组合时,才能获得额外的行。

现在,当我将查询更改为(从IS NULL更改为ISNULL)时:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL or ISNULL(g.groupname, null) IS NOT NULL

我得到了预期的结果:

adam, smith, null, null
yolanda, smith, null, null
null, null, members, 1

事实上,我甚至不需要更改where子句,以下查询也可以正常工作,并给出了上面显示的预期结果:

select u.first_name, u.last_name, ISNULL(g.groupname,null), r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL or g.groupname IS NOT NULL

所以,问题是,为什么? 为什么在我的SELECT语句中放入ISNULL会改变WHERE子句的工作方式?为什么它会有所作为呢? 为什么我的第一个查询无法正常工作?为什么只有在我添加OR时它才能运行 - 为什么不在没有它的情况下它会被破坏?

提前致谢。

我正在使用MS SQL Server 2008。

编辑:修正错字,澄清问题

5 个答案:

答案 0 :(得分:4)

我们发现这是Sql Server 2008中没有安装Service Pack的问题。尝试安装SP1或SP2。在我们的例子中,Service Pack解决了这个问题。

答案 1 :(得分:2)

ISNULL是一个函数,如果列为null,则返回指定的输入值,否则返回列值。

ISNULL(tbl.x, 'y') --returns 'y' if tbl.x is null otherwise the value of tbl.x

答案 2 :(得分:2)

我认为你要做的是获取所有用户和组,如果它是用户first_name和last_name将是某些东西,groupname将是NULL,但如果它是一个组,first_name和last_name将为NULL和groupname会有所作为。而是WHERE子句过滤结果,而不是定义数据连接的条件。我认为这会得到你想要的东西(假设r.isGroup == 1意味着它是一个团体):

要使用或多或少的原始查询,但要删除作为组或用户不存在的记录:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u 
    on u.userid = r.recipientId and r.isGroup != 1
left join groups g 
    on g.groupid = r.recipientId and r.isGroup == 1
where u.userid IS NOT NULL or g.groupid IS NOT NULL

但是,我认为具有内部联接的联合会表现得更好:

select u.first_name, u.last_name, NULL, r.isGroup
from recipients r
inner join users u on u.userid = r.recipientId
where r.isGroup != 1
union
select NULL, NULL, g.groupname, r.isGroup
from recipients r
inner join groups g on g.groupid = r.recipientId
where r.isGroup == 1

答案 3 :(得分:0)

来自SELECT子句:

  

u.groupname

来自WHERE子句的

  

g.groupname

进行这两场比赛,如果你看到任何不同的东西就知道。

答案 4 :(得分:0)

这似乎可以获得您想要的结果,但是如果NULLS瑞士有任何问题,那么您的数据可能无法正常运行:

select u.first_name, u.last_name, g.groupname, r.isGroup
from #recipients r
left join #users u on u.userid = r.recipientId
left join #groups g on g.groupid = r.recipientId
WHERE  g.groupname IS NOT NULL 
    OR ISNULL(r.IsGroup,0) > CASE WHEN g.groupid IS NOT NULL AND g.groupname IS NULL THEN -1 ELSE 0 END