过滤列表中的 NULL

发布于 2024-10-17 13:24:33 字数 966 浏览 5 评论 0 原文

为什么在子查询中过滤 NULL 不起作用? 我希望通过将 NULL 添加到允许值列表中来获得正确的结果,例如:

SELECT     ERP_ServiceProcess.fiStatusNew, RMA.IdRMA
FROM         ERP_ServiceProcess RIGHT OUTER JOIN
                      RMA ON ERP_ServiceProcess.fiRMA = RMA.IdRMA
WHERE  (ERP_ServiceProcess.fiStatusNew IN (NULL, 1, 7, 8))
order by ERP_ServiceProcess.fiStatusNew

这给出了错误的结果,因为 RMA 中的所有记录在子表 ERP_ServiceProcess(其中 ERP_ServiceProcess. fiStatusNew IS NULL) 被删除。

我必须使用这个(慢速)查询才能获得正确的结果:

SELECT     ERP_ServiceProcess.fiStatusNew, RMA.IdRMA
FROM         ERP_ServiceProcess RIGHT OUTER JOIN
                      RMA ON ERP_ServiceProcess.fiRMA = RMA.IdRMA
WHERE     (ERP_ServiceProcess.fiStatusNew IS NULL)
OR (ERP_ServiceProcess.fiStatusNew IN (1, 7, 8))
order by ERP_ServiceProcess.fiStatusNew

为什么我必须使用第二个慢速查询,尽管我使用了RIGHT OUTER JOIN并且我添加了NULL 到子查询?

先感谢您。

why does filter for NULL in subqueries does not work?
I hoped to get the correct result by add NULL to the list of allowed values, for example:

SELECT     ERP_ServiceProcess.fiStatusNew, RMA.IdRMA
FROM         ERP_ServiceProcess RIGHT OUTER JOIN
                      RMA ON ERP_ServiceProcess.fiRMA = RMA.IdRMA
WHERE  (ERP_ServiceProcess.fiStatusNew IN (NULL, 1, 7, 8))
order by ERP_ServiceProcess.fiStatusNew

This gives the incorrect result because all records in RMA that have no records in sub-table ERP_ServiceProcess(where ERP_ServiceProcess.fiStatusNew IS NULL) are dropped.

I must use this (slow) query to get the correct result:

SELECT     ERP_ServiceProcess.fiStatusNew, RMA.IdRMA
FROM         ERP_ServiceProcess RIGHT OUTER JOIN
                      RMA ON ERP_ServiceProcess.fiRMA = RMA.IdRMA
WHERE     (ERP_ServiceProcess.fiStatusNew IS NULL)
OR (ERP_ServiceProcess.fiStatusNew IN (1, 7, 8))
order by ERP_ServiceProcess.fiStatusNew

Why do i have to use the second, slow query although i used RIGHT OUTER JOIN and i've added NULL to the subquery?

Thank you in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

箹锭⒈辈孓 2024-10-24 13:24:33

它无法按您的预期工作,因为它扩展为一堆等于操作

fiStatusNew = NULL OR fiStatusNew = 1 OR fiStatusNew = 7 OR fiStatusNew = 8

anything = NULL 未知。

鉴于这种扩展,没有特别的理由认为使用 IS NULL 添加额外的 OR 本身会使事情变慢(额外的谓词可能会更改查询计划以使用不同的访问路径(如果统计数据表明匹配行的数量证明了这一点)

您在 CASE 操作中看到相同的行为

SELECT CASE NULL WHEN NULL THEN 'Yes' ELSE 'No' END /*Returns "No"*/

这是您应该特别注意逆操作的原因之一不在。如果列表包含任何 NULL 值,您将始终得到一个空结果集。

fiStatusNew NOT IN (NULL, 1,2)

将扩展为

fiStatusNew<> NULL 和 fiStatusNew<> 1 和 fiStatusNew<> 2

Unknown And True/False/Unknown And True/False/Unknown

Unknown simple-talk.com/sql/learn-sql-server/sql-and-the-snare-of- Three-valued-logic/" rel="nofollow">三值逻辑

It doesn't work as you expect as it gets expanded to a bunch of equals operations

fiStatusNew = NULL OR fiStatusNew = 1 OR fiStatusNew = 7 OR fiStatusNew = 8

and anything = NULL is unknown.

Given this expansion there's no particular reason to think that adding an additional OR using IS NULL would make things slower on its own (the additional predicate might change the query plan to use a different access path if the statistics lead it to belive that the number of matching rows warrants this though)

You see the same behaviour in the CASE operation

SELECT CASE NULL WHEN NULL THEN 'Yes' ELSE 'No' END /*Returns "No"*/

This is one reason why you should take particular care with the inverse operation NOT IN. If the list contains any NULL values you will always get an empty result set.

fiStatusNew NOT IN (NULL, 1,2)

Would expand to

fiStatusNew<> NULL and fiStatusNew<> 1 and fiStatusNew<> 2

or

Unknown And True/False/Unknown And True/False/Unknown

Which always evaluates to Unknown under three valued logic.

花伊自在美 2024-10-24 13:24:33

您可以尝试使用

ISNULL(ERP_ServiceProcess.fiStatusNew,0) IN (0, 1, 7, 8)

未经测试的但可能比第二个查询更快。

Could you try using

ISNULL(ERP_ServiceProcess.fiStatusNew,0) IN (0, 1, 7, 8)

Untested but might be quicker than the 2nd query.

最偏执的依靠 2024-10-24 13:24:33

“ERP_ServiceProcess.fiStatusNew IN (NULL)”的计算结果为“ERP_ServiceProcess.fiStatusNew = NULL”,并且始终为 false。 NULL 在 SQL Server 中被定义为“未知”,而不是“无值”。这就是为什么 NULL = NULL 或 NULL = @var (*) 总是评估为 false。如果有两个未知数,则无法检查它们是否相等。只有“is NULL”有效。

(*) 那么,对于 sql server,您可以将 ANSI_NULLS 设置为关闭但这并不是真正推荐的,因为它不是标准的 sql 行为。

'ERP_ServiceProcess.fiStatusNew IN (NULL)' evaluates to 'ERP_ServiceProcess.fiStatusNew = NULL' and that always is false. NULL is defined in sql server as 'unknown', not as 'no value'. That's why NULL = NULL or NULL = @var (*) always evaluates to false. If you have two unknowns, you cannot check if they are equal. Only 'is NULL' works.

(*) Well, for sql server, you can set ANSI_NULLS to off but that's not really recommended as it is not standard sql behaviour.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文