WHERE 子句中的 IS NOT NULL 和 ISNULL( str, NULL )
我有三个表(此处简化):
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
只有当我用 OR 组合两个 where 子句时,我才会得到额外的行。
现在,当我将查询更改为(从 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。
编辑:修复了拼写错误,澄清了问题
I have three tables (simplified here):
recipients: recipientId, isGroup
users: userId, first name, last name
groups: groupid, groupname
I want to retreive the first name / last name if the recipient is a user, and the group name if the recipient is a group. It's possible that the recipient is neither (i.e. a group that was deleted/no longer exists), so in that case I want to return nothing.
So this is what I did:
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
The above query is not returning expected results. I am getting this back:
adam, smith, null, null
yolanda, smith, null, null
null, null, members, 1
null, null, null, 1
The last row is unexpected, since clearly there is no group name (g.groupname is NULL) and r.IsGroup = 1.
When I do this:
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
I get expected results:
adam, smith, null, null
yolanda, smith, null, null
And when I do this:
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
I get expected results:
null, null, members, 1
It's only when I combine the two where clauses with an OR, do I get the additional row.
Now, when I change my query to (change from IS NULL to 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
I get the expected results:
adam, smith, null, null
yolanda, smith, null, null
null, null, members, 1
In fact, I don't even have to change the where clause, the following query works just as well too and gives me the expected result shown above:
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
SO, the question is, WHY? Why does putting ISNULL in my SELECT statement change how the WHERE clause works? Why does it make a difference at all? Why does my first query not work? Why is it that it fails to function only when I add the OR - why isn't it broken without it too?
Thanks in advance.
I am using MS SQL Server 2008.
edits: fixed typo, clarified question
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我们发现这是未安装服务包的 Sql Server 2008 中的问题。尝试安装 SP1 或 SP2。在我们的例子中,服务包解决了这个问题。
We found this to be an issue in Sql Server 2008 with no service packs installed. Try installing SP1 or SP2. In our case, the service pack resolved the issue.
ISNULL 是一个函数,如果列为空,则返回指定的输入值,否则返回列值。
ISNULL is a function that retuns the specified input value if the column is null otherwise the column value.
我相信你想做的是获取所有用户和组,如果是用户,则first_name和last_name将为NULL,groupname将为NULL,但如果它是一个组,first_name和last_name将为NULL,groupname将为NULL 。相反,您的 WHERE 子句会过滤结果,而不是定义数据连接方式的条件。我认为这将得到您正在寻找的内容(假设 r.isGroup == 1 意味着它是一个组):
或多或少地使用原始查询,但消除不作为组存在的记录或用户:
但是,我认为具有内部联接的联合会表现更好:
What I believe you're trying to do is get all users and groups, where if it's a user first_name and last_name will be something and groupname will be NULL, but if it's a group, first_name and last_name will be NULL and groupname will be something. Instead your WHERE clause is filtering the results, not defining the conditions of how your data is joined. I think this will get what you're looking for (assuming
r.isGroup == 1
means it's a group):To use more or less the original query but eliminate records that does not exist as a group or user:
However, I think a union with inner joins will perform better:
从 SELECT 子句:
来自 WHERE 子句的
让这两个匹配,如果您发现任何不同,请告诉我们。
From the SELECT clause:
from the WHERE clause:
Make those two match and let is know if you see anything different.
这似乎得到了您想要的结果,尽管如果 NULLS swiss-cheesing 您的数据存在任何问题,它可能不起作用:
This seems to get the results that you want, although if there are any gotchas from the NULLS swiss-cheesing your data it might not work: