SQL Server Find the number of return calls that were done by customer care within 30 minutes of the missed call

vql8enpb  于 9个月前  发布在  其他
关注(0)|答案(3)|浏览(92)

Consider a customer care center which receives calls from customers, Starttime and Endtime denotes the conversation start time and end time. Missed calls are the calls where no conversation happened. For any missed call, the customer care returns the call.

For below given table,

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

Find the number of return calls that were done by customer care within 30 minutes of the missed call.

Fourth row indicates one such return call.

Can anyone help a SQL query.

wz1wpwve

wz1wpwve1#

first you find the missed call, then you find the call back by customercare. And you find the time different

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
utugiqy6

utugiqy62#

@Squirrel beat me to it and my answer original answer was basically identical to his but I'll post what I put together as it also speaks to why APPLY is so excellent.

First, for optimal performance you would want a clustered index (or a covering index) on starttime. E.g.

CREATE CLUSTERED INDEX CL_CustomerCare_starttime ON dbo.CustomerCare(starttime);

Next, here's how you would do this using a JOIN (since you mentioned it):

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 = datediff(minute, cc.starttime, x.starttime)
FROM   dbo.CustomerCare AS cc
JOIN   dbo.CustomerCare AS x
  ON   cc.tonumber = x.fromnumber
 AND   x.tonumber  = cc.fromnumber
 AND   cc.starttime < x.starttime
WHERE datediff(minute, cc.starttime, x.starttime) <= 30;

Now, the APPLY version (this is what I put together before I saw Squirrels answer):

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;

Both Return:

fromnumber  tonumber    missedcalltime callbacktime timetocallback
----------- ----------- -------------- ------------ --------------
100         1800        18:40          18:55        15
300         1800        21:00          21:20        20

The first cool thing about APPLY is how I can use it to alias values to make my code "DRYer." (DRY = Don't Repeat Yourself). Since the expression datediff(minute, cc.starttime, x.starttime) is used multiple times, I can use APPLY to process the expression once then reference it multiple times as cb.t. Note the line:

CROSS APPLY (VALUES(datediff(minute, cc.starttime, x.starttime))) AS cb(t)

This is an example of how APPLY can make your code much cleaner and easier to debug.

The second and possibly more important example of how the powerful of APPLY is how you can join an outer query with a subquery. My two examples above are not Identical. Theoretically, if there were more than one "call back" within 30 minutes, the JOIN version would return them. Since this is likely an edge case, asking for the "TOP (1)" returned call within a half hour will be sufficient and will perform better. If you examine the execution plan for both queries - the join version reads more rows (28) when it self joints to CustomerCare, the APPLY version reads 22 rows. If you change TOP (1) to TOP ([anything greater than 1]) in the APPLY version it will read 28 rows. Again, this is another way you can use APPLY to tune performance.

Lastly, an important note about TOP in a subquery... If you remove the ORDER BY in the APPLY subquery the subquery will read 58 rows instead of 22 when an ORDER BY over a correctly indexed column is present.

djp7away

djp7away3#

select B.*
    , B.starttime - A.starttime
    , extract(minute from B.starttime - A.starttime) as callbacktime
from (
    select fromnumber, tonumber, starttime
    from test_customercare
    where starttime = endtime
) A, test_customercare B
where A.tonumber = B.fromnumber
    and A.fromnumber = B.tonumber 
    and extract(minute from B.starttime - A.starttime) < 30

here A is the table which holds missed calls…

相关问题