2014-06-20 14 views
2

我想通过嵌套的选择查询结果进行分组。我不明白如何以及为什么这个查询甚至运行良好。这是正确的方式来使用嵌套选择列上的组?我们在Oracle 11g上。在oracle中按语法混淆group,这是如何工作的?

select min(updated_at), max(updated_at), (select count(*) from domain_cdc where app_context_id = 1561 and domain_cdc_status = 'DONE') as done 
from domain_cdc where app_context_id = 1561 
group by ''; 

回答

2

好问题,因为它看起来非常像它不应该乍一看,但是当你深入挖掘时,它应该没有group by。它在解析器中看起来像一个错误,或者至少不一致。

嵌套选择不相关的,因此只需要执行一次,使得它的结果有效的常数,和documentation says

在含有GROUP BY子句的查询,的元素选择列表可以是聚合函数,GROUP BY表达式,常量或涉及其中之一的表达式。

select min(updated_at), max(updated_at), 42 as done 
from domain_cdc where app_context_id = 1561; 

...它运行的罚款,并有道理从文档所说:

如果与实际的计数值替换它,你将不会被需要的群体。不一致性是与嵌套的选择,如果你这样做,而不是它会抱怨:

select min(updated_at), max(updated_at), 
    (select count(*) from domain_cdc where app_context_id = 1561 
    and domain_cdc_status = 'DONE') as done 
from domain_cdc where app_context_id = 1561; 

SQL Error: ORA-00937: not a single-group group function 

但如果你有多余的group by null。因此,从一个角度来看,解析器不知道嵌套的select可以被看作一个常量,并且期望group by子句,但是它确实知道表达式不需要实际上在group by中。

如果嵌套选择有相关性,则group by null不会工作之一:

select min(updated_at), max(updated_at), 
    (select count(*) from domain_cdc dc2 
    where dc2.app_context_id = dc1.app_context_id 
    and domain_cdc_status = 'DONE') as done 
from domain_cdc dc1 
where app_context_id = 1561 
group by null; 

SQL Error: ORA-00979: not a GROUP BY expression 

所以它只是受了一点原始查询混淆。奇怪的是,但我认为大多是无害的,而且我意识到这并不完全回答这个问题......但它看起来与bug 18697654非常相似,如果这有什么帮助的话。


你不需要嵌套查询虽然这里,你可以使用一个case语句:

select min(updated_at), max(updated_at), 
    count(case when domain_cdc_status = 'DONE' then updated_at end) as done 
from domain_cdc where app_context_id = 1561; 

count只计算不空值;该案例使所有不是'DONE'为空,因此它们从该聚合中排除。由于您现在再没有非聚合列,并且解析可以理解发生了什么,因此您不需要group by

0

如果您还没有一个非常大的表,你可以尝试这样的:

SELECT distinct MAX (updated_at) OVER() AS max_updated_at, 
     MIN (updated_at) OVER() AS min_updated_at, 
     (SELECT COUNT (*) 
      FROM domain_cdc 
     WHERE domain_cdc_status = 'DONE') 
      AS cnt_domain_cdc 
    FROM domain_cdc 
    where app_context_id = 1561 

对于大表更好的解决方案(我相信)可以看起来像:

SELECT max_updated_at, min_updated_at, cnt_domain_cdc 
    FROM (SELECT 1 AS id, MAX (updated_at) AS max_updated_at, MIN (updated_at) AS min_updated_at 
      FROM domain_cdc 
     WHERE app_context_id = 1561) a 
     JOIN (SELECT 1 AS id, 
        (SELECT COUNT (*) 
         FROM domain_cdc 
         WHERE domain_cdc_status = 'DONE' AND app_context_id = 1561) 
         AS cnt_domain_cdc 
       FROM DUAL) b 
      ON a.id = b.id 
+0

这根本不是我的问题。 –