简体   繁体   中英

not a single-group group function using select case statement

I am writing below query which divides the two select query and calculate the percentage. But i am getting an error as not a single-group group function

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;

You are referencing an aggregate function ( COUNT(*) ) and an individual column expression ( r.cnt and o.cnt ) in the same SELECT query. This is not valid SQL unless a GROUP BY clause is added for the relevant individual columns.

It would be easier to provide a valid alternative it you could clarify what you'd like this query to return (given a sample schema and set of data). As a guess, I'd say you can simply substitute COUNT(*) with o.cnt to avoid the division by 0 issue. If there's some other logic expected to be present here, you'd need to clarify what that is.

You don't need to use joins. If I were you, I'd do:

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;

Here's a simple demo:

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

And just in case you aren't sure that doing the filtering of the count in the case statement returns the same as when you filter in the where clause, here's a demo that proves it:

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

It looks like you want to get a percentage of status not in 0,1, or 0 if there is no results.

Maybe this is what you want for the first line?

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

You don't need a cross join. Select the counts and do a division later on.

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

Boneist's answer is fine, but I would write it as:

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;

Here is the answer which works perfectly for me

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM