SubQueries和Group Functions可能存在Oracle-Bug

时间:2016-11-11 11:04:48

标签: sql oracle

任何人都可以解释为什么以下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的行不应该在结果中。

以下是第一个查询结果的屏幕截图:

enter image description here

我在以下版本上测试了它,总是得到相同的结果:

  • Oracle数据库11g企业版11.2.0.3.0版 - 64位生产
  • Oracle Database 12c企业版12.1.0.2.0版 - 64位生产

3 个答案:

答案 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和其他几个除外),MAXSUM或甚至两者都没有时在这种情况下,在空结果集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)

一个更简单的例子会导致同样的错误:

AVPlayerViewController

我必须承认我完全糊涂了。为什么过滤器没有消除记录,从而消除了任何结果集?

Explain Plan from TOAD