Wow, this was a real brain teaser. I'm sure this has all kinds of holes but here's a possible solution. First our test data:
If Exists(Select 1 From INFORMATION_SCHEMA.TABLES Where TABLE_NAME = 'recs')
DROP TABLE recs
GO
Create Table recs
(
Id int not null
, EmployeeId int not null
)
Insert recs(Id, EmployeeId)
Values (1,1) ,(2,1) ,(3,1) ,(4,2) ,(5,5) ,(6,1) ,(7,1) ,(8,1) ,(10,1)
,(11,1) ,(12,1) ,(13,2) ,(14,2) ,(15,2) ,(16,2)
Next, you will need a Tally or Numbers table that contains a sequence of numbers. I only put 500 elements in this one, but given the size of the data you may want more. The largest number in the Tally table should be bigger than the largest Id in the recs table.
Create Table dbo.Tally(Num int not null)
GO
;With Numbers As
(
Select ROW_NUMBER() OVER ( ORDER BY s1.object_id) As Num
From sys.columns as s1
)
Insert dbo.Tally(Num)
Select Num
From Numbers
Where Num < 500
Now for the actual solution. Basically, I used a series of CTEs to deduce the start and end point of the consecutive sequences.
; With
Employees As
(
Select Distinct EmployeeId
From dbo.Recs
)
, SequenceGaps As
(
Select E.EmployeeId, T.Num, R1.Id
From dbo.Tally As T
Cross Join Employees As E
Left Join dbo.recs As R1
On R1.EmployeeId = E.EmployeeId
And R1.Id = T.Num
Where T.Num <= (
Select Max(R3.Id)
From dbo.Recs As R3
Where R3.EmployeeId = E.EmployeeId
)
)
, EndIds As
(
Select S.EmployeeId
, Case When S1.Id Is Null Then S.Id End As [End]
From SequenceGaps As S
Join SequenceGaps As S1
On S1.EmployeeId = S.EmployeeId
And S1.Num = (S.Num + 1)
Where S.Id Is Not Null
And S1.Id Is Null
Union All
Select S.EmployeeId, Max( Id )
From SequenceGaps As S
Where S.Id Is Not Null
Group By S.EmployeeId
)
, SequencedEndIds As
(
Select EmployeeId, [End]
, ROW_NUMBER() OVER (PARTITION BY EmployeeId ORDER BY [End]) As SequenceNum
From EndIds
)
, StartIds As
(
Select S.EmployeeId
, Case When S1.Id Is Null Then S.Id End As [Start]
From SequenceGaps As S
Join SequenceGaps As S1
On S1.EmployeeId = S.EmployeeId
And S1.Num = (S.Num - 1)
Where S.Id Is Not Null
And S1.Id Is Null
Union All
Select S.EmployeeId, 1
From SequenceGaps As S
Where S.Id = 1
)
, SequencedStartIds As
(
Select EmployeeId, [Start]
, ROW_NUMBER() OVER (PARTITION BY EmployeeId ORDER BY [Start]) As SequenceNum
From StartIds
)
, SequenceRanges As
(
Select S1.EmployeeId, Start, [End]
From SequencedStartIds As S1
Join SequencedEndIds As S2
On S2.EmployeeId = S1.EmployeeId
And S2.SequenceNum = S1.SequenceNum
)
Select *
From SequenceGaps As SG
Where Exists(
Select 1
From SequenceRanges As SR
Where SR.EmployeeId = SG.EmployeeId
And SG.Id Between SR.Start And SR.[End]
And ( SR.[End] - SR.[Start] + 1 ) >= @SequenceSize
)
Using the final statement in the WHERE clause and @SequenceSize, you can control which sequences are returned.