Home > Software engineering >  SQL Server - Conditional Self Join
SQL Server - Conditional Self Join

Time:11-08

I have table as below:

CallDetails

Caller Receiver StartedAt StartedTimestamp LastModifiedTimestamp Outcome Direction
111111 91919 13.39 1636342600 1636342601 Missed Inbound
111111 91919 15.40 1636342828 1636343128 Missed Inbound
91919 111111 19.45 1636400728 1636401028 Answered Outbound
222222 91919 20.50 1636404628 1636405000 Missed Inbound

Expected output:

MissedCallDetails

Caller Receiver MissedCallAt CalledBackAt IsContactedAgain AnsweredMissedCall(In minutes)
111111 91919 15.40 19.45 YES 245
222222 91919 20.50 NO

The 2 major conditions to union are as below:

  1. When there is a returned call from the receiver to the same caller - it should considered IsContactedAgain = YES

  2. When call is not returned back after the LastModifiedTimestamp to the caller

I need a union of missed calls which are answered and unanswered.

So far, I have come up with below:

SELECT
    m.StartedAt AS MissedCallAt
    , r.StartedAt AS CalledBackAt
    , 'Y' AS IsContactedAgain
    , DATEDIFF(mi, m.StartedAt, r.StartedAt) AS 'CalledIn(Minutes)'
FROM 
    CallDetails m, CallDetails r
WHERE 
    CONVERT(char(10), M.StartedAt,126) = DATEADD(Day, -1, CAST( GETDATE() AS Date)) 
    AND m.UserId IS NULL 
    AND m.Outcome = 'Missed call'
    AND r.Recipient = m.Caller
    AND r.StartedTimestamp > m.LastModifiedTimestamp
    AND r.Direction = 'Outbound'
ORDER BY 
    m.StartedAt, r.StartedAt

Thanks.

CodePudding user response:

A left join can be useful here to include the missed calls without callback.

untested notepad scribble

SELECT m.StartedAt AS MissedCallAt
, r.StartedAt AS CalledBackAt
, CASE WHEN r.StartedAt IS NOT NULL THEN 'YES' ELSE 'NO' END AS IsContactedAgain
, DATEDIFF(minute, m.StartedAt, r.StartedAt) AS [CalledIn(Minutes)] 
FROM CallDetails m
LEFT JOIN CallDetails r 
  ON r.Direction = 'Outbound'
 AND r.Recipient = m.Caller
 AND r.Caller = m.Recipient
 AND r.StartedTimestamp > m.LastModifiedTimestamp
WHERE m.Direction = 'Inbound' 
  AND m.Outcome = 'Missed call'
  AND m.StartedAt > DATEDIFF(SECOND,'1970-01-01', DATEADD(Day, -1, CAST(GETUTCDATE() AS DATE)))
ORDER BY m.StartedAt, r.StartedAt

CodePudding user response:

I'd start with looking at the latest missed inbound calls per caller and callee.

Then, there should be only one callback it seems, but I'd write my query such that it can deal with multiple callbacks. Say, they call back, then see that they missed explaining a detail and call back the next day again. For this case we must decide whether to take the first callback time or the last one. A lateral join (OUTER APPLY) is a good way to deal with such situation.

with latest_missed as
(
  select top(1) with ties *
  from calldetails
  where direction = 'Inbound' and outcome = 'Missed'
  order by rank() over (partition by caller, receiver order by startedat desc)
)
select
  lm.caller,
  lm.receiver,
  lm.startedat as missed_call_at,
  callback.startedat as called_back_at,
  case when callback.startedat is null then 'No' else 'Yes' end as is_contacted_again,
  datediff(minute, lm.startedat, callback.startedat) as answered_missed_call_in_minutes
from latest_missed lm
outer apply
(
  select top(1) *
  from calldetails cd
  where cd.caller = lm.receiver
    and cd.receiver = lm.caller
    and cd.startedat > lm.startedat
    and cd.direction = 'Outbound'
    order by cd.startedat desc
) callback
order by lm.caller, lm.receiver;

You may also want to consider how to treat outbound callbacks that are not 'Answered', but failed for some reason.

  • Related