Home > Software design >  SQL - Finding/Matching "pairs" in the same table, by event/date
SQL - Finding/Matching "pairs" in the same table, by event/date

Time:03-15

I'm having issues developing a working solution/query for the case I bring you.

I have a table that receives agent data. What I need is a way to find out the matching "pairs", by day and event, in order to insert them in a temp table, so they can be worked. There can be several entries/pairs in the same day.

A sample of what i'm talking about:

Event Date AGENT Event Type Event Subtype
2022-03-14 09:00 AGENT 1 VOICE CHANNEL LOGIN
2022-03-14 11:10 AGENT 1 BREAK START
2022-03-14 11:20 AGENT 1 BREAK END
2022-03-14 13:10 AGENT 1 VOICE CHANNEL LOGOUT
2022-03-14 14:00 AGENT 1 VOICE CHANNEL LOGIN
2022-03-14 15:50 AGENT 1 BREAK START
2022-03-14 16:00 AGENT 1 BREAK END
2022-03-14 18:10 AGENT 1 VOICE CHANNEL LOGOUT
2022-03-14 10:00 AGENT 2 TICKET CHANNEL LOGIN
2022-03-14 12:00 AGENT 2 BREAK START
2022-03-14 12:10 AGENT 2 BREAK END
2022-03-14 14:00 AGENT 2 TICKET CHANNEL LOGOUT

In this case the 1st agent 1 'voice channel' 'login' should be paired with the first agent 1 'voice channel' 'logout', the first 'break' 'start' should be paired with the first 'break' 'end', the second agent 1 'voice channel' 'login' with the second agent 1 'voice channel' 'logout' and the second 'break' 'start' with the second 'break' 'end', and so forth.

The destination temp table will have the columns 'Agent', 'event', 'event start' and 'event end'.

@Coder1991 The final temp table should read something like this:

AGENT Event Type Event Start Event End
AGENT 1 VOICE CHANNEL 2022-03-14 09:00 2022-03-14 13:00
AGENT 1 BREAK 2022-03-14 11:10 2022-03-14 11:20
AGENT 1 VOICE CHANNEL 2022-03-14 14:00 2022-03-14 18:00
AGENT 1 BREAK 2022-03-14 15:50 2022-03-14 16:00
AGENT 2 TICKET CHANNEL 2022-03-14 10:00 2022-03-14 14:00
AGENT 2 BREAK 2022-03-14 12:00 2022-03-14 12:10

Any suggestions / inputs are appreciated.

Thank you all in advance, and have a great week.

CodePudding user response:

You can use a Gaps-And-Islands trick for this.

A ranking can be calculated via using a SUM OVER a flag.
And the flag is the start of the types per agent.

Once you have the rank, it just a matter of aggregation.

SELECT AGENT, [Event Type]
, MIN(CASE WHEN [Event SubType] IN ('LOGIN', 'START') THEN [Event Date] END) AS [Event Start] 
, MAX(CASE WHEN [Event SubType] IN ('LOGOUT', 'END')  THEN [Event Date] END) AS [Event End] 
FROM
(
SELECT [Event Date], AGENT, [Event Type], [Event Subtype]
, Rnk = SUM(IIF([Event SubType] IN ('LOGIN', 'START'), 1, 0)) 
        OVER (PARTITION BY AGENT, [Event Type], CAST([Event Date] AS DATE) ORDER BY [Event DATE])
FROM agent_events 
) q
GROUP BY AGENT, [Event Type], CAST([Event Date] AS DATE), Rnk
ORDER BY AGENT, [Event Start];
GO
AGENT   | Event Type     | Event Start      | Event End       
:------ | :------------- | :--------------- | :---------------
AGENT 1 | VOICE CHANNEL  | 2022-03-14 09:00 | 2022-03-14 13:10
AGENT 1 | BREAK          | 2022-03-14 11:10 | 2022-03-14 11:20
AGENT 1 | VOICE CHANNEL  | 2022-03-14 14:00 | 2022-03-14 18:10
AGENT 1 | BREAK          | 2022-03-14 15:50 | 2022-03-14 16:00
AGENT 2 | TICKET CHANNEL | 2022-03-14 10:00 | 2022-03-14 14:00
AGENT 2 | BREAK          | 2022-03-14 12:00 | 2022-03-14 12:10

Demo on db<>fiddle here

CodePudding user response:

Please try the below approach

 declare @tbl table([Event Date] datetime,AGENT varchar(10),[Event Type] 
 varchar(20)
,[Event Subtype] varchar(20)
 )

insert into @tbl
values('2022-03-14 09:00','AGENT 1','VOICE CHANNEL','LOGIN')
,('2022-03-14 11:10','AGENT 1','BREAK','START')
,('2022-03-14 11:20','AGENT 1','BREAK','END')
,('2022-03-14 13:10','AGENT 1','VOICE CHANNEL','LOGOUT')
,('2022-03-14 14:00','AGENT 1','VOICE CHANNEL','LOGIN')
,('2022-03-14 15:50','AGENT 1','BREAK','START')
,('2022-03-14 16:00','AGENT 1','BREAK','END')
,('2022-03-14 18:10','AGENT 1','VOICE CHANNEL','LOGOUT')
,('2022-03-14 19:00','AGENT 1','VOICE CHANNEL','LOGIN')
,('2022-03-14 20:10','AGENT 1','VOICE CHANNEL','LOGOUT')
,('2022-03-14 10:00','AGENT 2','TICKET CHANNEL','LOGIN')
,('2022-03-14 12:00','AGENT 2','BREAK','START')
,('2022-03-14 12:10','AGENT 2','BREAK','END')
,('2022-03-14 14:00','AGENT 2','TICKET CHANNEL','LOGOUT')


select *
, case when ROW_NUMBER()over(partition by agent,[Event Type] order by [Event Date]) % 2
 != 0 then [Event Date] else null end 
[Event Start]
,case when ROW_NUMBER()over(partition by agent,[Event Type] order by [Event Date]) % 2
 = 0 then [Event Date] else null end 
[Event End]
into #temp
from @tbl

;with cte as(
select AGENT,[Event Type],[Event Start]
,lead([Event End],1)over(partition by agent,[Event Type] order by [Event Date]) [Event End]
from
#temp
)
select *
from cte 
where [Event Start] is not null
order by AGENT,[Event Start] 

drop table #temp
  • Related