Sql 没有使用select case语句的单个组函数

Sql 没有使用select case语句的单个组函数,sql,oracle,group-by,case-when,Sql,Oracle,Group By,Case When,我正在写下面的查询,它将两个select查询分开并计算百分比。但我得到了一个错误,因为不是一个单一的组函数 您正在同一个SELECT查询中引用聚合函数COUNT*和单个列表达式r.cnt和o.cnt。除非为相关的各个列添加GROUP BY子句,否则这是无效的SQL 提供一个有效的替代方案会更容易,因为您可以在给定一个示例模式和一组数据的情况下澄清希望此查询返回的内容。作为猜测,我认为您可以简单地用o.cnt替换COUNT*,以避免除以0的问题。如果这里预期会出现其他逻辑,您需要澄清这是什么。看起

我正在写下面的查询,它将两个select查询分开并计算百分比。但我得到了一个错误,因为不是一个单一的组函数


您正在同一个SELECT查询中引用聚合函数COUNT*和单个列表达式r.cnt和o.cnt。除非为相关的各个列添加GROUP BY子句,否则这是无效的SQL


提供一个有效的替代方案会更容易,因为您可以在给定一个示例模式和一组数据的情况下澄清希望此查询返回的内容。作为猜测,我认为您可以简单地用o.cnt替换COUNT*,以避免除以0的问题。如果这里预期会出现其他逻辑,您需要澄清这是什么。

看起来您希望获得的状态百分比不在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 

你不需要交叉连接。选择计数,然后进行除法

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

这是一个非常适合我的答案

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

您不需要使用联接。如果我是你,我会:

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语句中过滤count时返回的结果与在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

Boneist的回答很好,但我可以这样写:

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;

@GordonLinoff r是在交叉联接之前定义的。如果您以可读的方式格式化代码,则更容易判断。到目前为止,我的两个内部选择查询都返回0。我不明白在哪里我必须使用GROUPBY子句,因为在语句本身的情况下,我得到整数作为返回值,对吗?它不返回行数或行数something@Rahul-引擎无法保证您的子查询返回标量值,它希望您优化查询以确保不会出现不明确的分组问题。如上所述,没有明显的理由需要在初始SELECT语句中使用函数COUNT*。只要使用o.cnt就可以了:如果R.cnt不是0,但o.cnt是@那是不可能的,不是吗?r集是o集的一个子集。另一种方法是可能的,但在任何情况下,我认为count*=0的OP意味着根本没有结果,我想在这种情况下,我只需要将o.cnt的值设置为0,因为只有别名o select条件返回0时,nit才会给出一个可被0整除的错误error@jpw除非在子查询之间运行一个日期边界,否则不会发生这种情况:假定这实际上不会发生,但是检查R.CNT并不能在这里添加任何内容。这些解决方案都没有像COUNT*那样检查源表中的“any”行,但这样的检查实际上不会阻止被0除。也许不会,但这并不能真正解决为什么会发生错误的问题。您还为status和date_created添加了一个groupby,这将导致返回多行。我不认为这是OP的本意。@Boniest即使我使用联接或不使用联接,它肯定会返回相同的结果,对吗?有很多方法可以改变查询逻辑?是的,你会得到相同的结果,只是希望更快。我刚刚更新了我的答案,加入了一个演示,对case语句中要计数的行进行过滤,返回的结果与在where子句中过滤行,然后进行计数*的结果相同。
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;