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