如何统计 Informix SQL 的差异?

How to count the difference in Informix SQL?

我正在计算呼叫中心的评分呼叫数和平均评分:

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 个额定销售电话和 4 个额定服务电话)。

我还可以计算总调用次数(已评级和未评级):

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 个销售电话和 4 个服务电话)。

但我只想计算未评级的电话。 SQL 请求:

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

运行缓慢并产生不正确的结果,例如

|queue    |average   |count   |
+---------+----------+--------+
|sales    |0         |69      |
|service  |0         |16      |

(69 个未评级的销售电话和 16 个未评级的服务电话 - 不正确)。

因此未评级的计数 = 总计 - 已评级,我无法构建一个 SQL 我可以得到这个结果的地方。

期望的结果应该是:

|queue    |average   |count   |
+---------+----------+--------+
|sales    |0         |9       |
|service  |0         |0       |

(21-12=9 个未评级的销售电话和 4-4=0 个未评级的服务电话)。

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    |

最后我为 dbfiddle.uk 准备了一个脚本来玩这个场景:

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);     
GO
12 rows affected
select queue, count(*) as total
from callrecord
group by queue
GO
queue | 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
GO
queue | 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
GO
queue | 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
GO
queue | unrated
:---- | ------:
SALES |       8

db<>fiddle here

由于不想统计child table, calldata,匹配的记录只统计callrecord层记录,考虑将 EXISTS 子句(或 IN)与相关子查询一起使用:

-- 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

Online Demo