Oracle如何从(子查询)简化选择计数(*)?

时间:2017-04-26 15:59:36

标签: sql oracle

我被要求尝试简化count()查询,但我不知道从哪里开始,查询是这样的:

SELECT COUNT( 1 )
FROM (
        SELECT DISTINCT a.col,b.colx,c.coly
        FROM  a
            JOIN b on a.id = b.id
            JOIN c on b.id = c.id
        WHERE a.xyz = 'something'
        AND   b.hijk = 'something else'
        AND c.id IN (
                SELECT cid
                FROM cwa
                WHERE csid = 22921
            )
        ORDER BY
            e.create_timestamp DESC
    );

我被告知可以简化SELECT COUNT(1) FROM (subquery),如何做到这一点?

我尝试了几件事,但结果与上面的查询不同。

2 个答案:

答案 0 :(得分:6)

除非您在rownum上过滤结果,否则子查询中的order-by并不有用(有时会出错,具体取决于上下文)。您可以使用连接替换内部子查询:

SELECT COUNT(*)
FROM (
    SELECT DISTINCT a.col,b.colx,c.coly
    FROM  a
    JOIN b on a.id = b.id
    JOIN c on b.id = c.id
    JOIN cwa on c.id cwa.cid
    WHERE a.xyz = 'something'
    AND   b.hijk = 'something else'
    AND   cwa.csid = 22921
);

如果您可以识别出未在您选择的三个列中的任何一列中出现的字符,您甚至可以在没有子查询的情况下执行此操作,因此您可以将其用作分隔符;例如如果你从未有过波浪线,你可以这样做:

SELECT COUNT(DISTINCT a.col ||'~'|| b.colx ||'~'|| c.coly)
FROM  a
JOIN b on a.id = b.id
JOIN c on b.id = c.id
JOIN cwa on c.id cwa.cid
WHERE a.xyz = 'something'
AND   b.hijk = 'something else'
AND   cwa.csid = 22921;
但是,这是否更简单或更清楚是一个意见问题。

由于count()只接受一个参数,并且您想要计算这三列的(不同)组合,此机制将所有三个连接成一个字符串,然后计算该字符串的外观。添加了分隔符,以便您可以区分不明确的列值,例如CTE中的人为示例:

with cte (col1, col2) as (
  select 'The', 'search' from dual
  union all select 'These', 'arch' from dual
)
select col1, col2,
  col1 || col2 as bad,
  col1 ||'~'|| col2 as good
from cte;

COL1  COL2   BAD         GOOD        
----- ------ ----------- ------------
The   search Thesearch   The~search  
These arch   Thesearch   These~arch  

简单的“坏”'连接两行出现相同;通过添加分隔符来使“好”'版本你仍然可以区分它们,所以计算不同的连接值得到正确的答案:

with cte (col1, col2) as (
  select 'The', 'search' from dual
  union all select 'These', 'arch' from dual
)
select count(distinct col1 || col2) as bad_count,
  count (distinct col1 ||'~'|| col2) as good_count
from cte;

 BAD_COUNT GOOD_COUNT
---------- ----------
         1          2

如果col1以波浪号结尾,或者col2以代字号开头,则您会回到歧义:

with cte (col1, col2) as (
  select 'The~', 'search' from dual
  union all select 'The', '~search' from dual
)
select col1, col2,
  col1 || col2 as bad,
  col1 ||'~'|| col2 as still_bad
from cte;

COL1 COL2    BAD         STILL_BAD   
---- ------- ----------- ------------
The~ search  The~search  The~~search 
The  ~search The~search  The~~search 

因此分隔符必须是您在任何值中都找不到的东西。

答案 1 :(得分:0)

尝试使用

    SELECT count(DISTINCT a.col)
    FROM  a
        JOIN b on a.id = b.id
        JOIN c on b.id = c.id
    WHERE a.xyz = 'something'
    AND   b.hijk = 'something else'
    AND c.id IN (
            SELECT cid
            FROM cwa
            WHERE csid = 22921
        );

因为order by会增加你不必要的执行时间