Reputation: 2916
Given a table messages
with the following fields:
id | Number
customer_id | Number
source | VARCHAR2
...
I want to know how many messages each customer has, but I want to differentiate between messages where source
equals to 'xml'
and all other sources.
My query so far
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;
which gives me a result similar to this:
customer_id | xml | count
----------------------------
1 | xml | 12
1 | manual | 34
2 | xml | 54
3 | xml | 77
3 | manual | 1
...
This is rather ugly in two ways:
case
statement in both the field list and in the group listQ: Is it possible to formulate a query, such that the result looks like this instead?
customer_id | xml | manual
--------------------------
1 | 12 | 34
2 | 54 | 0
3 | 11 | 1
Upvotes: 0
Views: 69
Reputation: 4624
There is other way by using decode function apart from CASE:
SELECT cust_id,
COUNT(DECODE(source,'xml','xml'))"XML",
COUNT(DECODE(source,'manual','manual'))"manual"
FROM MESSAGES
GROUP BY cust_id;
But, this won't show result when you have null as source.
Upvotes: 0
Reputation: 8113
This will work, it doesn't appear you have a source called 'manual'. COUNT or SUM will give you the same difference.
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
This will allow for zero to appear where you usually would see a NULL value, your sample has a zero rather than a null.
Upvotes: 1
Reputation:
Here is a fancy solution (it does almost exactly what vkp's solution does), using the PIVOT operation introduced in Oracle 11.1. Note how the distinction between 'xml' and all others (including NULL) is dealt with in the subquery.
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))
;
Upvotes: 0
Reputation: 49270
Use conditional aggregation.
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
This assumes the source
column is non null
. If it can be null
use coalesce
or nvl
in the case
expression so the comparison gives you expected results.
Upvotes: 3
Reputation:
You are looking for conditional aggregation:
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
This works because aggregates ignore NULL
values and the result of the CASE
will be NULL
if source
does not contain the value from the case condition.
Upvotes: 4