任何人都可以解释为什么以下Query返回两行而不仅仅是一行?
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;
Oracle提供两行是否正确?在我看来,c1 = ASDF的行不应该在结果中。
以下是第一个查询结果的屏幕截图:
我在以下版本上测试了它,总是得到相同的结果:
答案 0 :(得分:3)
这不是错误。聚合函数是您看到此意外结果的原因。下面是它的工作原理。如果查询没有返回任何行,SUM()
函数以及MAX()
函数将返回NULL(生成1行)。当您的查询执行时,优化器应用predicate pushing
转换并且您的原始查询变为(不会发布整个跟踪,仅发布已转换的查询):
SELECT "from$_subquery$_001"."C1" "C1",
"from$_subquery$_001"."C2" "C2"
FROM (
(SELECT 'ASDF' "C1",MAX(SUM(1)) "C2"
FROM "SYS"."DUAL" "DUAL"
WHERE 'ASDF'<>'ASDF' [1]-- predicate pushed into the view
GROUP BY "DUAL"."DUMMY" )
UNION
(SELECT 'JKLÖ' "C1",
1 "C2"
FROM "SYS"."DUAL" "DUAL"
WHERE 'JKLÖ'<>'ASDF')) "from$_subquery$_001"
[1]由于谓词推送你的第一个子查询没有返回任何行,当一个聚合函数(count
和其他几个除外),MAX
或SUM
或甚至两者都没有时在这种情况下,在空结果集NULL
上使用将返回 - 第二个子查询返回1行+ 1行,从而生成您正在查看的2行结果集。
这是一个简单的演示:
create table empty_table (c1 varchar2(1));
select 'aa' literal, nvl(max(c1), 'NULL') as res
from empty_table
LITERAL RES
------- ----
aa NULL
1 row selected.
答案 1 :(得分:1)
它绝对看起来像一个bug。
我真的不知道如何阅读解释计划,但现在就是这样。在我看来,谓词已被推送到只有一个UNION成员,它已被转换为&#34; NULL IS NOT NULL&#34;这很奇怪。
请注意,字符串可以更改为&#39; a&#39;和&#39; b&#39; (所以我们不使用特殊字符),UNION和UNION ALL产生相同的错误,并且错误似乎是由第一个分支中的MAX(SUM(1))触发的;只需将其替换为NULL或其他任何“简单&#34;”,甚至使用SUM(1)(不使用MAX)都可以使查询正常工作。
已添加:奇怪的是,如果我将MAX(SUM(1))
更改为MAX(1)
或SUM(1)
,或者只是将其更改为文字编号{{1} },查询工作正常 - 但解释计划仍显示相同的奇怪谓词,&#34; NULL IS NOT NULL&#34;。所以,似乎问题是谓词不会被推到联合的两个分支,而不是谓词转换。 (即使这并不能解释为什么1
在结果集的额外行中显示为c2
。) MORE ADDED (请参阅下面的评论) - 因为它事实证明,谓词被推到UNION的两个分支,这正是导致问题的原因(正如尼古拉斯在他的回答中所解释的那样)。
NULL
答案 2 :(得分:0)