patternsqlMinor
Assign number incrementally, reset when value changes
Viewed 0 times
incrementallynumbervaluechangeswhenresetassign
Problem
declare @t table (scanCode varchar(6), dates datetime, flag varchar(1))
insert @t ( scanCode, dates, flag)
select '182086','01 Jul 2020','P' union all
select'182086','02 Jul 2020','P' union all
select'182086','03 Jul 2020','A' union all
select'182086','04 Jul 2020','A' union all
select'182086','06 Jul 2020','P' union all
select'182086','07 Jul 2020','P' union all
select'182086','08 Jul 2020','P' union all
select'182086','09 Jul 2020','P' union all
select'182086','10 Jul 2020','A' union all
select'182086','11 Jul 2020','A' union all
select'182086','13 Jul 2020','A' union all
select'182086','14 Jul 2020','A'
select scanCode
, dates
, flag
, prn = row_number() over (partition by scanCode,flag order by scanCode, dates)
from @t t
order by t.datesCurrently the result is:
scanCode dates flag prn
182086 2020/07/01 P 1
182086 2020/07/02 P 2
182086 2020/07/03 A 1
182086 2020/07/04 A 2
182086 2020/07/06 P 3
182086 2020/07/07 P 4
182086 2020/07/08 P 5
182086 2020/07/09 P 6
182086 2020/07/10 A 3
182086 2020/07/11 A 4
182086 2020/07/13 A 5
182086 2020/07/14 A 6I want the result to be:
scanCode dates flag prn
182086 2020/07/01 P 1
182086 2020/07/02 P 2
182086 2020/07/03 A 1
182086 2020/07/04 A 2
182086 2020/07/06 P 1
182086 2020/07/07 P 2
182086 2020/07/08 P 3
182086 2020/07/09 P 4
182086 2020/07/10 A 1
182086 2020/07/11 A 2
182086 2020/07/13 A 3
182086 2020/07/14 A 4scancode, dates is primary key in my table.Solution
Another way to solve this is to think of it as a variation of the gaps and islands pattern:
That output gives us a way to identify groups:
All that is left to do is number rows within each group. The full query is:
The output is:
Execution plan:
db<>fiddle online demo
SELECT *, diff = (N.rn1 - N.rn2)
FROM
(
SELECT
*,
rn1 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.dates),
rn2 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.flag, T.dates)
FROM @t AS T
) AS N;That output gives us a way to identify groups:
All that is left to do is number rows within each group. The full query is:
WITH
N AS
(
-- Previous code
SELECT
*,
rn1 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.dates),
rn2 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.flag, T.dates)
FROM @t AS T
)
SELECT
N.scanCode,
N.dates,
N.flag,
prn = ROW_NUMBER() OVER (
PARTITION BY N.scanCode, (N.rn1 - N.rn2)
ORDER BY N.dates)
FROM N;The output is:
Execution plan:
db<>fiddle online demo
Code Snippets
SELECT *, diff = (N.rn1 - N.rn2)
FROM
(
SELECT
*,
rn1 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.dates),
rn2 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.flag, T.dates)
FROM @t AS T
) AS N;WITH
N AS
(
-- Previous code
SELECT
*,
rn1 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.dates),
rn2 = ROW_NUMBER() OVER (
PARTITION BY T.scanCode
ORDER BY T.flag, T.dates)
FROM @t AS T
)
SELECT
N.scanCode,
N.dates,
N.flag,
prn = ROW_NUMBER() OVER (
PARTITION BY N.scanCode, (N.rn1 - N.rn2)
ORDER BY N.dates)
FROM N;Context
StackExchange Database Administrators Q#274679, answer score: 3
Revisions (0)
No revisions yet.