给定一个包含以下字段的表messages
:
id | Number
customer_id | Number
source | VARCHAR2
...
我想知道每个客户有多少条消息,但我想区分source
等于'xml'
的消息和所有其他来源。
到目前为止我的查询
SELECT customer_id,
case when source = 'xml' then 'xml' else 'manual' end as xml,
count(*)
FROM MESSAGES
GROUP BY customer_id,
case when source = 'xml' then 'xml' else 'manual' end;
给我一个类似的结果:
customer_id | xml | count
----------------------------
1 | xml | 12
1 | manual | 34
2 | xml | 54
3 | xml | 77
3 | manual | 1
...
这在两个方面相当丑陋:
case
语句问:是否可以制定查询,以便结果看起来像这样?
customer_id | xml | manual
--------------------------
1 | 12 | 34
2 | 54 | 0
3 | 11 | 1
答案 0 :(得分:4)
您正在寻找条件聚合:
SELECT customer_id,
count(case when source = 'xml' then 1 end) as xml_count,
count(case when source <> 'xm' then 1 end) as manual_count
FROM MESSAGES
GROUP BY customer_id
这是有效的,因为聚合忽略NULL
值,如果CASE
不包含案例条件中的值,NULL
的结果将为source
。
答案 1 :(得分:3)
使用条件聚合。
SELECT customer_id,
sum(case when source = 'xml' then 1 else 0 end) as xml,
sum(case when source <> 'xml' then 1 else 0 end) as manual
FROM MESSAGES
GROUP BY customer_id
这假定source
列不是null
。如果在null
表达式中coalesce
可以使用nvl
或case
,那么比较会为您提供预期结果。
答案 2 :(得分:1)
这样可行,看起来你没有一个名为'manual'的来源。 COUNT或SUM会给你相同的差异。
SELECT
customer_id
,ISNULL(COUNT(CASE WHEN source = 'xml' THEN 1 END),0) xml
,ISNULL(COUNT(CASE WHEN source <> 'xml' OR source IS NULL THEN 1 END),0) manual
FROM Messages
GROUP BY customer_id
这将允许零出现在您通常会看到NULL值的位置,您的样本为零而不是null。
答案 3 :(得分:0)
使用Oracle 11.1中引入的PIVOT操作,这是一个奇特的解决方案(它几乎与vkp的解决方案完全相同)。注意如何在子查询中处理'xml'和所有其他(包括NULL)之间的区别。
select *
from (select customer_id, case when source = 'xml' then 'xml' else 'other' as source
from messages)
pivot (count(*) for source in ('xml' as xml, 'other' as other))
;
答案 4 :(得分:0)
除了CASE之外,使用解码功能还有其他方法:
SELECT cust_id,
COUNT(DECODE(source,'xml','xml'))"XML",
COUNT(DECODE(source,'manual','manual'))"manual"
FROM MESSAGES
GROUP BY cust_id;
但是,当您将null作为源时,这将不会显示结果。