簡體   English   中英

Oracle如何簡化(子查詢)的選擇計數(*)?

[英]Oracle How to simplify a select count(*) from (subquery)?

我被要求嘗試簡化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) ,這怎么做?

我已經嘗試了幾件事,但是結果與上面的查詢不同。

除非您在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 

因此分隔符必須是在任何值中都找不到的東西。

嘗試使用

    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會增加您不必要的執行時間

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM