I’m counting number of rated calls and average rating in callcenter:
select cr.queue, ROUND(AVG(TO_NUMBER(cd.datavalue)),2) as average, count(*) as count from callrecord cr left join calldata cd on cd.callid=cr.callid where cd.datakey="qrate1" group by queue
|queue |average |count | +---------+----------+--------+ |sales |3.92 |12 | |service |3.75 |4 |
(12 rated calls for sales and 4 rated calls for service).
I can also count number of total calls (rated and unrated):
select cr.queue, 0 as average, count(*) as count from callrecord cr group by queue
|queue |average |count | +---------+----------+--------+ |sales |0 |21 | |service |0 |4 |
(21 total calls for sales and 4 total calls for service).
But I want to count only unrated calls. SQL request:
select cr.queue, 0 as average, count(*) as count from callrecord cr left join calldata cd on cd.callid=cr.callid where cd.datakey!="qrate1" group by queue
runs slowly and produce incorrect result, e.g.
|queue |average |count | +---------+----------+--------+ |sales |0 |69 | |service |0 |16 |
(69 unrated calls for sales and 16 unrated calls for service – incorrect).
Hence count of unrated = total – rated, I can’t build an SQL where I can get this result.
Desired result should be:
|queue |average |count | +---------+----------+--------+ |sales |0 |9 | |service |0 |0 |
(21-12=9 unrated calls for sales and 4-4=0 unrated calls for service).
Example of CALLDATA table:
|callid |datakey |datavalue | +---------+----------+-----------+ |181 |ANI |1234567890 | |181 |DNIT |2345678901 | |181 |IVR_CHOICE|SALES | |182 |ANI |1234567890 | |182 |DNIT |2345678901 | |182 |QRATE1 |1 | |183 |ANI |1234567890 | |183 |DNIT |2345678901 | |183 |LANG |ENGLISH |
Finally I have prepared a script for dbfiddle.uk to play with this scenario:
select * into calldata from (values ('181','ANI','1234567890') , ('181','DNIT','2345678901') , ('181','IVR_CHOICE','SALES') , ('182','ANI','1234567890') , ('182','DNIT','2345678901') , ('182','QRATE1','1') , ('183','ANI','1234567890') , ('183','DNIT','2345678901') , ('183','LANG','ENGLISH') ) z(callid,datakey,datavalue); select * into callrecord from (values ('181','SALES') , ('182','SALES' ) , ('183','SALES' ) ) z(callid,queue); GO12 rows affected
select queue, count(*) as total from callrecord group by queue GOqueue | total :---- | ----: SALES | 3
select cr.queue, count(*) as rated from callrecord cr left join calldata cd on cr.callid=cd.callid where cd.datakey='QRATE1' group by queue GOqueue | rated :---- | ----: SALES | 1
select cr.queue, count(*) as unrated from callrecord cr left join calldata cd on cr.callid=cd.callid where cd.datakey<>'QRATE1' group by queue GOqueue | unrated :---- | ------: SALES | 8
select cr.queue, SUM(CASE WHEN cd.datakey='QRATE1' THEN 0 ELSE 1 END) as unrated from callrecord cr left join calldata cd on cr.callid=cd.callid group by queue GOqueue | unrated :---- | ------: SALES | 8
db<>fiddle here
Advertisement
Answer
Since you do not want to count the child table, calldata, matched records but only callrecord level records, consider using EXISTS clause (or IN) with correlated subquery:
-- EXISTS select cr.queue, count(*) as rated from callrecord cr where exists ( select 1 from calldata cd where cd.callid = cr.callid and cd.datakey = 'QRATE1' ) group by queue -- NOT EXISTS select cr.queue, count(*) as rated from callrecord cr where not exists ( select 1 from calldata cd where cd.callid = cr.callid and cd.datakey = 'QRATE1' ) group by queue