【问题标题】:IS NOT NULL and ISNULL( str, NULL ) in WHERE clauseWHERE 子句中的 IS NOT NULL 和 ISNULL(str, NULL)
【发布时间】:2011-11-17 07:42:46
【问题描述】:

我有三个表(这里简化):

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

所以,问题是,为什么? 为什么将 ISNULL 放在我的 SELECT 语句中会改变 WHERE 子句的工作方式? 为什么它会有所不同? 为什么我的第一个查询不起作用?为什么只有当我添加 OR 时它才会起作用 - 为什么没有它它也不会损坏?

提前致谢。

我使用的是 MS SQL Server 2008。

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

【问题讨论】:

  • 你能确保 g.groupname 包含 NULL 值而不是像“NULL”这样的字符串。有时它可能会让您感到困惑。
  • 是的。我确实确定了。此外,如果没有, ISNULL(g.groupname, null) IS NOT NULL 不会有任何区别。

标签: sql sql-server isnull


【解决方案1】:

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

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

【讨论】:

  • 那么这是等价的:ISNULL(g.groupname, null) IS NOT NULL 和 g.groupName IS NOT NULL,对吧?由于当 g.groupname 为 null 时,ISNULL 将解析为 null。但是,我的查询表明它不等效。
【解决方案2】:

从 SELECT 子句:

u.组名

来自 WHERE 子句:

g.组名

使这两个匹配,如果您发现任何不同之处,请告知。

【讨论】:

  • 抱歉,错字。在 SELECT 子句中也应该是 g.groupname。
【解决方案3】:

我相信你想要做的是获取所有用户和组,如果它是用户 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

【讨论】:

  • 有可能即使 r.IsGroup = 1,它也不是一个组(或与此相关的任何东西)。我想省略在任何一个表中都找不到的结果,这只发生在 r.IsGroup = 1 并且它不在组表中(因为可以删除组而发生)。我做不到。
  • 谢谢。但是我已经知道如何得到我想要的结果,我只是想知道为什么我的第一个查询不起作用,而第二个却不起作用——唯一的区别是使用了 ISNULL。此外,您的第一个查询给了我同样的问题 - 我的原始查询给了我。它不起作用并返回应该被过滤掉的额外行。
  • 这很奇怪。要么是 SQL Server 造成的异常行为,要么是数据与您期望的不一样。您可以将u.useridg.groupid 添加到选择结果中,以确保它们是您期望的值。对于您的查询,如果 groupids 和 userids 重叠,除非您在 on 子句中处理该条件,否则您将面临很大的意外结果风险。
  • 您也可以将where u.userid IS NOT NULL or g.groupid IS NOT NULL 更改为where (r.isGroup != 1 and u.userid IS NOT NULL) or (r.isGroup == 1 and g.groupid IS NOT NULL),但如果数据符合预期,则没有必要这样做——而且它的性能会很糟糕。抱歉,我无法直接解决 ISNULL 问题,因为似乎其他地方存在问题导致意外结果。
  • groupids 和 userids 永远不会重叠。绝不。我很确定数据符合我的预期 - 否则 ISNULL 也不起作用:(
【解决方案4】:

这似乎得到了你想要的结果,尽管如果 NULLS swiss-cheesing 你的数据有任何陷阱,它可能不起作用:

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

【讨论】:

    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 2010-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-14
      • 2014-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多