Reputation: 35
I have a following table (clients):
client | status | email | phone
---------------------------------
001 | active | yes | yes
002 | inactive | yes | yes
003 | inactive | yes | no
004 | deceased | no | no
005 | active | yes | no
006 | deceased | no | no
007 | active | yes | yes
008 | inactive | no | yes
009 | active | no | no
010 | inactive | yes | yes
I need results to show stats of inactive clients compared to all clients, ie.
status | email | phone | total
--------------------------------
inactive | yes | yes | 2
inactive | yes | no | 1
inactive | no | yes | 1
all | yes | yes | 4
all | yes | no | 2
all | no | yes | 1
all | no | no | 3
Since CASE checks met conditions, I don't know how to get a fraction of results in first condition and then all results.
I used these two selects:
SELECT CASE WHEN STATUS = 'inactive' THEN STATUS
WHEN STATUS IS NOT NULL THEN 'all' END "STATUS",
EMAIL, PHONE,
COUNT(CLIENT) TOTAL
FROM CLIENTS
GROUP BY CASE WHEN STATUS = 'inactive' THEN STATUS
WHEN STATUS IS NOT NULL THEN 'all' END,
EMAIL, PHONE
ORDER BY 1 DESC, 2 DESC, 3 DESC;
-------
SELECT 'all' AS STATUS, EMAIL, PHONE,
COUNT(CLIENT) TOTAL
FROM CLIENTS
GROUP BY EMAIL, PHONE
ORDER BY 2 DESC, 3 DESC;
Obviously, first part is not working as intended, but I put it here to better showcase my question.
Is it possible to do it in one query?
Upvotes: 1
Views: 665
Reputation: 966
You can use below query:
with stat ( status) as (
select'inactive' from dual
union all
select 'all' from dual
),
clients (client, status, email, phone) as (
select 001, 'active', 'yes', 'yes' from dual union all
select 002, 'inactive', 'yes', 'yes' from dual union all
select 003, 'inactive', 'yes', 'no' from dual union all
select 004, 'deceased', 'no', 'no' from dual union all
select 005, 'active', 'yes', 'no' from dual union all
select 006, 'deceased', 'no', 'no' from dual union all
select 007, 'active', 'yes', 'yes' from dual union all
select 008, 'inactive', 'no', 'yes' from dual union all
select 009, 'active', 'no', 'no' from dual union all
select 010, 'inactive', 'yes', 'yes' from dual
)
SELECT stat.status, EMAIL, PHONE, COUNT(*) TOTAL
FROM CLIENTS, stat
where stat.status = clients.status or stat.status = 'all'
GROUP BY stat.status, EMAIL, PHONE
ORDER BY 1 DESC, 2 DESC, 3 DESC
Upvotes: 2
Reputation: 191265
Yout first query doesn't need the case expression, you can just filter on the single status you want; and then union with the second query:
-- CTE for sample data
with clients (client, status, email, phone) as (
select 001, 'active', 'yes', 'yes' from dual union all
select 002, 'inactive', 'yes', 'yes' from dual union all
select 003, 'inactive', 'yes', 'no' from dual union all
select 004, 'deceased', 'no', 'no' from dual union all
select 005, 'active', 'yes', 'no' from dual union all
select 006, 'deceased', 'no', 'no' from dual union all
select 007, 'active', 'yes', 'yes' from dual union all
select 008, 'inactive', 'no', 'yes' from dual union all
select 009, 'active', 'no', 'no' from dual union all
select 010, 'inactive', 'yes', 'yes' from dual
)
-- actual query
SELECT STATUS, EMAIL, PHONE, COUNT(*) TOTAL
FROM CLIENTS
WHERE STATUS = 'inactive'
GROUP BY STATUS, EMAIL, PHONE
UNION ALL
SELECT 'all' AS STATUS, EMAIL, PHONE, COUNT(*) TOTAL
FROM CLIENTS
GROUP BY EMAIL, PHONE
ORDER BY 1 DESC, 2 DESC, 3 DESC;
STATUS EMAIL PHONE TOTAL
-------- ----- ----- ----------
inactive yes yes 2
inactive yes no 1
inactive no yes 1
all yes yes 4
all yes no 2
all no yes 1
all no no 3
Just for fun, you could do this while only hitting the table once, by using conditional aggregation:
select email, phone,
count(case when status = 'inactive' then client end) as inactive,
count(*) as total
from clients
group by email, phone
order by 1 desc, 2 desc;
EMAIL PHONE INACTIVE TOTAL
----- ----- ---------- ----------
yes yes 2 4
yes no 1 2
no yes 1 1
no no 0 3
and then unpivoting:
select status, email, phone, total
from (
select email, phone,
count(case when status = 'inactive' then client end) as inactive,
count(*) as total
from clients
group by email, phone
)
unpivot (total for status in (inactive as 'inactive', total as 'all'))
where total > 0
order by 1 desc, 2 desc, 3 desc;
STATUS EMAIL PHONE TOTAL
-------- ----- ----- ----------
inactive yes yes 2
inactive yes no 1
inactive no yes 1
all yes yes 4
all yes no 2
all no yes 1
all no no 3
but unless you have a lot of data in your real scenario you probably don't need to make it that complicated.
Upvotes: 3
Reputation: 37473
Try below with Union
SELECT STATUS, EMAIL, PHONE,COUNT(CLIENT) TOTAL
from CLIENTS where status='inactive'
group by STATUS,EMAIL, PHONE
union
SELECT 'All' as STATUS, EMAIL, PHONE,COUNT(CLIENT) TOTAL
from CLIENTS
group by EMAIL, PHONE
Upvotes: 2