Create
table
T1
(Id
int
identity
primary
key
,
VoucherNo
varchar
(4),
TransNo
(10)
)
Insert
into
values
(
'V100'
'Trns1'
),(
'V101'
'V102'
'V103'
'V104'
'V106'
;
WITH
cte
AS
SELECT
*
CAST
SUBSTRING
(VoucherNo, 2, 3)
INT
) - ROW_NUMBER() OVER (
ORDER
BY
Grp
FROM
min
(VoucherNo)
FirstVoucherNo
max
LastVoucherNo
count
(*)
Quantity
GROUP
,Grp
CREATE
TABLE
Person
(PersonID
IDENTITY(1,1)
PRIMARY
KEY
PersonName
(3),
SigninDate
date
);
INSERT
INTO
VALUES
'AAA'
'20130301'
),
'20130302'
'20130305'
'20130306'
'20130307'
'BBB'
'20130303'
/* Solution for a *Pre* SQL 2012 version
The
first
CTE groups the PersonName
and
assign a
group
number
a row identifier
for
each
*/
CTE_GROUPS
*,
DENSE_RANK() OVER (
PersonName)
GroupID,
ROW_NUMBER() OVER(PARTITION
SigninDate) RowNum
/*
second
CTE will find the border
the GAPs
CTE_GAPS
C2.PersonName,
C2.SigninDate GapStart,
C1.SigninDate GapEnd
CTE_GROUPS C1
INNER
JOIN
CTE_GROUPS C2
ON
C1.GroupID=C2.GroupID
C1.RowNum=C2.RowNum+1
AND
ISNULL
(DATEDIFF(
DAY
,C2.Signindate,C1.SigninDate),0)>1
Personname,
LAG(P.SigninDate) Over(Partition
by
P.PersonName
Order
By
P.PersonName,p.Signindate) GapStart ,
SigninDate GapEnd,
,LAG(P.SigninDate) Over(Partition
P.PersonName,p.Signindate),P.SigninDate)-1) GapDays
Person P)
P.PersonName,
C.CalendarDate
MASTER..Calendar C
CROSS
CTE_GAPS P
WHERE
GapDays>0
BETWEEN
DATEADD(
,1,P.GapStart )
,-1,P.GapEnd)
Congratulations on winning the gold medal! blogs.technet.com/.../technet-guru-awards-july-2013.aspx
Naomi, your article was featured on MSDN blogs here: blogs.msdn.com/.../transact-sql-guru-gaps-and-islands-problem.aspx
Thank you for all your TechNet Guru contributions!
It was also featured on the Wiki Ninjas blog: blogs.technet.com/.../july-t-sql-guru-naomi-n-wins-again-with-quot-gaps-and-islands-problem-quot.aspx
Congrats on being featured on the home page of TechNet Wiki!
Thanks
Naomi N edited Revision 15. Comment: Added link
Naomi N edited Revision 16. Comment: Added another link