2015-09-07 140 views
0

我在下面的查詢中寫下哪個分隔兩個select查詢並計算百分比。但我得到一個錯誤的not a single-group group function不是使用select case語句的單個組的組函數

select CASE WHEN COUNT(*) = 0 THEN 0 ELSE round((r.cnt/o.cnt)*100,3) END from 
    (Select count(*) as cnt from O2_CDR_HEADER WHERE STATUS NOT IN(0,1) and DATE_CREATED > (SYSDATE - 1)) r cross join 
    (Select count(*) as cnt from O2_CDR_HEADER WHERE DATE_CREATED > (SYSDATE - 1)) o; 
+0

@GordonLinoff'r'在'cross join'之前定義。 – PinnyM

+1

如果您以可讀的方式格式化代碼,將會更容易判斷。 –

回答

2

你並不需要使用加入了答案。如果我是你,我會做:

select case when count(*) = 0 then 0 
      else round(100 * count(case when status not in (0, 1) then 1 end)/count(*), 3) 
     end non_0_or_1_status_percentage 
from o2_cdr_header 
where date_created > sysdate - 1; 

這裏有一個簡單的演示:

with t as (select 1 status from dual union all 
      select 2 status from dual union all 
      select 3 status from dual union all 
      select 2 status from dual union all 
      select 4 status from dual union all 
      select 5 status from dual union all 
      select 6 status from dual union all 
      select 7 status from dual union all 
      select 1 status from dual union all 
      select 0 status from dual union all 
      select 1 status from dual) 
select case when count(*) = 0 then 0 
      else round(100 * count(case when status not in (0, 1) then 1 end)/count(*), 3) 
     end col1 
from t 
where 1=0; 

     COL1 
---------- 
     0 

以防萬一你不知道,這樣做計數的過濾在case語句返回相同的,當你在WHERE子句中過濾器,下面是證明了一個演示它:

with t as (select 1 status from dual union all 
      select 2 status from dual union all 
      select 3 status from dual union all 
      select 2 status from dual union all 
      select 4 status from dual union all 
      select 5 status from dual union all 
      select 6 status from dual union all 
      select 7 status from dual union all 
      select 1 status from dual union all 
      select 0 status from dual union all 
      select 1 status from dual) 
select 'using case statement' how_count_filtered, 
     count(case when status not in (0, 1) then 1 end) cnt 
from t 
union all 
select 'using where clause' how_count_filtered, 
     count(*) cnt 
from t 
where status not in (0, 1); 

HOW_COUNT_FILTERED   CNT 
-------------------- ---------- 
using case statement   7 
using where clause   7 
+0

@Boniest即使我使用連接或沒有它肯定會返回相同的結果嗎?可以有很多方法來改變查詢邏輯? – Andrew

+0

是的,你會得到相同的結果,只有 - 希望 - 更快。 – Boneist

+1

我剛剛更新了我的答案,其中包括一個演示,在case語句中對行進行過濾的過程返回的結果與您在where子句中過濾行並且然後執行count(*)的過程相同。 – Boneist

2

你引用一個聚合函數(COUNT(*)),並在同一個SELECT查詢單個列表達式(r.cnto.cnt)。這是無效的SQL,除非爲相關的各個列添加了GROUP BY子句。

提供一個有效的替代方案會更容易,您可以闡明您希望此查詢返回的內容(給出示例模式和一組數據)。作爲一個猜測,我會說你可以簡單地用替換爲o.cnt以避免被0問題分割。如果這裏還有其他一些邏輯出現,那麼你需要澄清這是什麼。

+0

我的內部選擇查詢都返回0到現在。我不明白在哪裏我必須使用group by clause beacuse在情況下,當語句本身我得到整數號碼作爲返回值的權利?它不返回行數或東西 – Andrew

+0

@Rahul - 引擎無法保證您的子查詢返回標量值,並且它會期望您優化查詢以確保不會發生模糊分組問題。正如我上面所說的,沒有明顯的理由需要在最初的'SELECT'語句中使用函數COUNT(*)。只需使用'o.cnt'並開心:) – PinnyM

1

它看起來像你想要得到的狀態百分比不是在0,1或0,如果沒有結果。

也許這是你想要的第一行?

SELECT CASE WHEN (R.CNT = 0 AND O.CNT = 0) THEN 0 ELSE ROUND((R.CNT *100.0/O.CNT),3) END 
+1

如果'R.CNT'不是0,但是'O.CNT'是? ;) – PinnyM

+0

@PinnyM那不可能發生,可以嗎? 'r'集合是'o'集合的一個子集。反過來也是可能的,但無論如何,我認爲OP對count(*)= 0意味着根本沒有結果,這將做到這一點。 – jpw

+1

我認爲在這種情況下,我必須設置它只爲o。cnt爲0,因爲只用於別名o選擇條件,如果它返回0 nit會給出一個可被0整除的錯誤 – Andrew

1

您不需要交叉連接。選擇計數並稍後再進行分組。

select case when ocnt > 0 then round((rcnt/ocnt)*100,3) 
     else 0 end 
from 
(
select 
CASE WHEN STATUS NOT IN(0,1) and DATE_CREATED > (SYSDATE - 1) 
THEN COUNT(*) END as rcnt, 
CASE WHEN DATE_CREATED > (SYSDATE - 1) 
THEN COUNT(*) END as ocnt 
from O2_CDR_HEADER 
group by status, date_created 
) t 
+0

也許不是,但這並沒有真正解決錯誤發生的原因。您還爲status和date_created添加了GROUP BY,這將導致返回多行。我不認爲這是OP的意圖。 – PinnyM

0

這裏是一個完美的作品對我來說

select CASE WHEN (o.cnt = 0) THEN 0 ELSE round((r.cnt/o.cnt)*100,3) END from 
(Select count(*) as cnt from O2_CDR_HEADER WHERE STATUS NOT IN(0,1) and DATE_CREATED > (SYSDATE - 1)) r cross join 
(Select count(*) as cnt from O2_CDR_HEADER WHERE DATE_CREATED > (SYSDATE - 1)) o 
1

Boneist的答案是好的,但我會WR將它作爲:

select coalesce(round(100 * avg(case when status not in (0, 1) then 1.0 else 0 
           end), 3), 0) as non_0_or_1_status_percentage 
from o2_cdr_header 
where date_created > sysdate - 1;