如果没有使用group by子句返回的行,则select语句应将计数返回零。

时间:2019-03-28 11:16:10

标签: oracle

我有一个表格student_info,它的列为“状态”,状态可以是P(存在),A(不存在),S(病),T(转移),L(左)。

我正在寻找期望的输出,如下所示。

status  count(*)
P       12
S       1
A       2
T       0
L       0

但是输出如下:

Status   Count(*)
P          12
S           1
A           2

我们需要针对状态T和L的行以及计数为零的行,尽管数据库中不存在任何记录。

2 个答案:

答案 0 :(得分:1)

@mkuligowski的方法很接近,但是您需要在CTE之间提供所有可能的状态值的外部联接,然后需要计算实际匹配的条目:

-- CTE to generate all possible status values
with stored_statuses (status) as (
            select 'A' from dual
  union all select 'L' from dual
  union all select 'P' from dual
  union all select 'S' from dual
  union all select 'T' from dual
)
select ss.status, count(si.status)
from stored_statuses ss
left join student_info si on si.status = ss.status
group by ss.status;

STATUS COUNT(SI.STATUS)
------ ----------------
P                    12
A                     2
T                     0
S                     1
L                     0

CTE充当虚拟表,其中包含您要计数的五个状态。然后,将外部联接到您的真实表中-外部联接意味着即使没有匹配项,CTE的行也将包括在内-然后对表中相匹配的行进行计数。这样就可以包括零计数。

您也可以使用收藏夹来完成此操作:

select ss.status, count(si.status)
from (
  select column_value as status from table(sys.odcivarchar2list('A','L','P','S','T'))
) ss
left join student_info si on si.status = ss.status
group by ss.status;

最好有一个物理表来保存这些值(及其描述);然后,您还可以具有主键/外键关系,以在现有表中强制使用允许的值。


如果所有状态值实际上都出现在表中,但是您有一个过滤器恰好排除了其中某些行的所有行,那么您可以从表本身获取所有(使用的)值的列表,而不用硬对其进行编码。

如果您的初始查询是这样的,请使用完整的过滤器:

select si.status, count(*)
from student_info si
where si.some_condition = 'true'
group by si.status;

然后,您可以使用子查询从未经过滤的表中获取所有不同的值,从该表中进行外部联接,然后将过滤器用作外部联接条件的一部分:

select ss.status, count(si.status)
from (
  select distinct status from student_info
) ss
left join student_info si on si.status = ss.status
and si.some_condition = 'true'
group by ss.status;

它不能保留为where子句(至少在这里,它适用于外部联接的右侧),因为那样会覆盖外部联接并将其有效地转换回内部联接。

答案 1 :(得分:0)

您应该将状态存储在某个地方(可能在另一个表中)。否则,您可以使用子查询列出它们:

with stored_statuses as (
  select 'P' code, 'present' description from dual
  union all 
  select 'A' code, 'absent' description from dual
  union all 
  select 'S' code, 'ill' description from dual
  union all 
  select 'T' code, 'transfer' description from dual
  union all 
  select 'L' code, 'left' description from dual
)
select ss.code, count(*) from student_info si
left join stored_statuses ss on ss.code = si.status
group by ss.code
相关问题