Sql 查找客户服务部在未接来电后30分钟内完成的回电次数

Sql 查找客户服务部在未接来电后30分钟内完成的回电次数,sql,sql-server,tsql,Sql,Sql Server,Tsql,假设一个客户服务中心接收来自客户的呼叫,Starttime和Endtime表示对话的开始时间和结束时间。未接来电是指没有通话的来电。对于任何未接来电,客户服务部门都会返回电话 对于下表 CREATE TABLE CustomerCare (fromnumber INT, tonumber INT, starttime DATETIME,endtime DATETIME) INSERT INTO CustomerCare (fromnumber,tonumber,starttime,endtim

假设一个客户服务中心接收来自客户的呼叫,Starttime和Endtime表示对话的开始时间和结束时间。未接来电是指没有通话的来电。对于任何未接来电,客户服务部门都会返回电话

对于下表

CREATE TABLE CustomerCare (fromnumber INT, tonumber INT, starttime DATETIME,endtime DATETIME)

INSERT INTO CustomerCare (fromnumber,tonumber,starttime,endtime) 
VALUES
(100,1800,'2019-08-13 18:40:00','2019-08-13 18:40:00'),
(1800,100,'2019-08-13 18:55:00','2019-08-13 18:57:00'),
(200,1800,'2019-08-13 19:30:00','2019-08-13 19:30:00'),
(1800,200,'2019-08-13 20:05:00','2019-08-13 20:10:00'),
(300,1800,'2019-08-13 21:00:00','2019-08-13 21:00:00'),
(1800,300,'2019-08-13 21:20:00','2019-08-13 21:25:00'),
(400,1800,'2019-08-13 07:00:00','2019-08-13 07:00:00'),
(500,1800,'2019-08-13 8:00:00','2019-08-13 8:05:00')

查找客户服务部在未接来电后30分钟内完成的回电次数

第四行表示一个这样的回叫


任何人都可以帮助进行SQL查询。

首先您可以找到未接来电,然后您可以通过customercare找到回拨电话。你发现时间不同了

select  *
from    CustomerCare mc
        cross apply -- get call back time
        (   
            select  top 1 *
            from    CustomerCare x
            where   x.fromnumber    = mc.tonumber
            and     x.tonumber  = mc.fromnumber
            and     x.starttime > mc.starttime
            order by x.starttime
        ) cb
where   mc.starttime = mc.endtime  -- missed call
and     datediff(minute, mc.starttime, cb.starttime) > 30 -- time different between 
                                                          -- missed call and callback

@松鼠打败了我,我的答案和他的答案基本相同,但我会把我的答案贴在一起,因为这也说明了为什么APPLY如此优秀

首先,为了获得最佳性能,您需要在starttime上使用聚集索引(或覆盖索引)。例如

CREATE CLUSTERED INDEX CL_CustomerCare_starttime ON dbo.CustomerCare(starttime);
接下来,您将如何使用联接来实现这一点(因为您提到了它):

关于APPLY的第一件很酷的事情是我如何使用它来别名值,使我的代码成为“干燥剂”(DRY=不要重复你自己)。由于表达式
datediff(minute,cc.starttime,x.starttime)
被多次使用,因此我可以使用APPLY处理表达式一次,然后将其多次引用为cb.t。请注意这一行:

CROSS APPLY (VALUES(datediff(minute, cc.starttime, x.starttime))) AS cb(t)
这是一个示例,说明了APPLY如何使代码更干净、更易于调试

关于APPLY的强大功能的第二个也是可能更重要的例子是如何将外部查询与子查询连接起来。我上面的两个例子并不相同。理论上,如果在30分钟内有多个“回调”,则加入版本将返回它们。由于这可能是一种边缘情况,因此在半小时内请求“TOP(1)”返回呼叫就足够了,而且性能会更好。如果检查两个查询的执行计划-当联接版本自联接到CustomerCare时,将读取更多行(28),应用版本将读取22行。如果在应用版本中将TOP(1)更改为TOP([大于1的任何内容]),它将读取28行。同样,这是另一种可以使用APPLY优化性能的方法


最后,关于子查询中TOP的一个重要注意事项。。。如果在“应用”子查询中删除ORDER BY,则当存在索引正确的列上的ORDER BY时,子查询将读取58行而不是22行

第四排似乎是在未接来电后30分钟内没有回电话。未接来电时间为19:30,回电时间为20:05?您希望
在30分钟内
不要在30分钟内
?感谢@Umair Ramzan的评论。。。让我们考虑大于或等于30分钟。任何帮助谢谢您的解决方案@Squirrel。如果我们不使用交叉应用,它会是什么样子。。有什么办法吗?原因是什么?我不太了解交叉申请。这对我来说很有用。。但是,如果没有弄错的话,
CROSS-APPLY
是从
SQLServer2005
开始引入的,已经有10多年了。这不是一个新功能。如果你不使用它,你会错过很多是的。。明白了,松鼠。。我发现它和内部连接很相似。。。顺便说一句,谢谢
SELECT 
  cc.fromnumber,
  cc.tonumber, 
  missedcalltime = CAST(CAST(cc.starttime AS TIME) AS CHAR(5)),
  callbacktime   = CAST(CAST(x.starttime AS TIME) AS CHAR(5)),
  timetocallback = cb.t
FROM   dbo.CustomerCare AS cc
CROSS APPLY 
(
  SELECT TOP (1) x.starttime
  FROM     dbo.CustomerCare AS x
  WHERE    cc.tonumber = x.fromnumber
  AND      x.tonumber  = cc.fromnumber
  AND      cc.starttime < x.starttime
  ORDER BY x.starttime
) AS x
CROSS APPLY (VALUES(datediff(minute, cc.starttime, x.starttime))) AS cb(t)
WHERE       cb.t <= @callback;
fromnumber  tonumber    missedcalltime callbacktime timetocallback
----------- ----------- -------------- ------------ --------------
100         1800        18:40          18:55        15
300         1800        21:00          21:20        20
CROSS APPLY (VALUES(datediff(minute, cc.starttime, x.starttime))) AS cb(t)