任何人都可以解释为什么以下查询返回两行而不只是一行?
SELECT *
FROM (SELECT 'ASDF' c1, MAX (SUM (1)) c2
FROM DUAL
GROUP BY dummy
UNION
SELECT 'JKLÖ' c1, 1 c2
FROM DUAL)
WHERE c1 != 'ASDF';
--another Version with the same wrong result:
SELECT *
FROM (SELECT 1 c1, MAX (SUM (1)) c2
FROM DUAL
GROUP BY dummy
UNION all
SELECT 2 c1, 1 c2
FROM DUAL)
WHERE c1 != 1;
Run Code Online (Sandbox Code Playgroud)
Oracle提供两行是否正确?在我看来,c1 = ASDF的行不应该在结果中.
这是第一个查询结果的屏幕截图:
我在以下版本上测试了它,总是得到相同的结果:
小智 1
它看起来绝对像一个错误。
我真的不知道如何阅读解释计划,但就是这样。在我看来,谓词已被推送到仅一个 UNION 成员,并且已转换为“NULL IS NOT NULL”,这非常奇怪。
请注意,字符串可以更改为“a”和“b”(因此我们不使用特殊字符),UNION 和 UNION ALL 会产生相同的错误,并且该错误似乎是由 MAX(SUM(1) 触发的) 在第一个分支;只需将其替换为 NULL 或其他“简单”的内容,甚至使用 SUM(1) (不带 MAX)即可使查询正常工作。
添加:奇怪的是,如果我更改MAX(SUM(1))为MAX(1)or SUM(1),或者如果我只是将其更改为文字 number 1,则查询可以正常工作 - 但解释计划仍然显示相同的奇怪谓词,“NULL IS NOT NULL”。因此,问题似乎在于谓词没有被推送到并集的两个分支,而不是谓词转换。(甚至这也不能解释为什么c2出现NULL在结果集中的额外行中。)更多添加(请参阅下面的评论) - 事实证明,谓词被推送到 UNION 的两个分支,而这正是导致问题(正如尼古拉斯在他的回答中解释的那样)。
Plan hash value: 1682090214
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 32 | 2 (0)| 00:00:01 |
| 1 | VIEW | | 2 | 32 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | SORT AGGREGATE | | 1 | 2 | | |
| 4 | HASH GROUP BY | | 1 | 2 | | |
|* 5 | FILTER | | | | | |
| 6 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
| 7 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - filter(NULL IS NOT NULL)
Run Code Online (Sandbox Code Playgroud)