请考虑这个脚本:
Declare @tbl Table
(
F1 int,
F2 int,
Year int,
Month tinyint
)
Insert into @tbl
values
(10, 1, 2020, 1),
(10, 1, 2020, 2),
(10, 1, 2020, 3),
(10, 1, 2020, 4),
(10, 2, 2020, 5),
(10, 1, 2020, 6),
(10, 1, 2020, 7),
(11, 1, 2020, 1),
(11, 1, 2020, 2),
(11, 2, 2020, 3),
(11, 2, 2020, 4),
(11, 1, 2020, 5),
(12, 1, 2020, 1),
(12, 1, 2020, 2),
(12, 1, 2020, 3),
(12, 1, 2020, 4)
我写了这个查询:
Select
F1, F2, year, month,
Row_number() over (partition by F1, F2 order by year, month) as rownumber,
Rank() over (partition by F1, F2 order by year, month) as rnk
From
@tbl
Order by
f1, f2, year, month
此查询返回此结果集:
F1 | F2 | 年份 | 月 | 行号 | Rnk |
---|---|---|---|---|---|
10 | 1 | 2020 | 1 | 1 | 1 |
10 | 1 | 2020 | 2 | 2 | 2 |
10 | 1 | 2020 | 3 | 3 | 3 |
10 | 1 | 2020 | 4 | 4 | 4 |
10 | 1 | 2020 | 6 | 5 | 5 |
10 | 1 | 2020 | 7 | 6 | 6 |
10 | 2 | 2020 | 5 | 1 | 1 |
11 | 1 | 2020 | 1 | 1 | 1 |
11 | 1 | 2020 | 2 | 2 | 2 |
11 | 1 | 2020 | 5 | 3 | 3 |
11 | 2 | 2020 | 3 | 1 | 1 |
11 | 2 | 2020 | 4 | 2 | 2 |
12 | 1 | 2020 | 1 | 1 | 1 |
12 | 1 | 2020 | 2 | 2 | 2 |
12 | 1 | 2020 | 3 | 3 | 3 |
但我想要这个结果:
F1 | F2 | 年份 | 月 | 顺序 |
---|---|---|---|---|
10 | 1 | 2020 | 1 | 1 |
10 | 1 | 2020 | 2 | 2 |
10 | 1 | 2020 | 3 | 3 |
10 | 1 | 2020 | 4 | 4 |
10 | 2 | 2020 | 5 | 1 |
10 | 1 | 2020 | 6 | 1 |
10 | 1 | 2020 | 7 | 2 |
11 | 1 | 2020 | 1 | 1 |
11 | 1 | 2020 | 2 | 2 |
11 | 2 | 2020 | 3 | 1 |
11 | 2 | 2020 | 4 | 2 |
11 | 1 | 2020 | 5 | 1 |
12 | 1 | 2020 | 1 | 1 |
12 | 1 | 2020 | 2 | 2 |
12 | 1 | 2020 | 3 | 3 |
12 | 1 | 2020 | 4 | 4 |
即在每组相同的F1值中,
按年然后月顺序,
但在每次 F2 更改时重置年月序列号。
怎样才能达到我想要的结果?谢谢
这基本上是变相的差距和孤岛问题。 这里,每个“岛”是属于同一个
F1
块的一组记录,其中 F2
值在年份和月份中没有按顺序变化。 我们可以生成一个伪组来跟踪这些记录,然后使用 ROW_NUMBER()
来生成最终的序列值。 请注意,当 F1
块结束或 F2
值发生变化时,此伪组值重置为 1。
WITH cte AS (
SELECT *, CASE WHEN LAG(F2) OVER (PARTITION BY F1 ORDER BY Year, Month) != F2 THEN 1 ELSE 0 END AS flag
FROM @tbl
),
cte2 AS (
SELECT *, SUM(flag) OVER (PARTITION BY F1 ORDER BY Year, Month) grp
FROM cte
)
SELECT F1, F2, Year, Month,
ROW_NUMBER() OVER (PARTITION BY F1, grp ORDER BY Year, Month) AS seq
FROM cte2
ORDER BY F1, Year, Month;
确定边界后(F1分组序列中F2发生变化的时刻),您可以从所有后续位置中减去最后一个边界的位置:
With bordered as
(
Select
*,
Row_number() over win as pos,
case when F2 = lag(F2) over win then null else Count(1) over win - 1 end as ignore_before
From
@tbl
Window win As (partition by F1 order by year, month)
)
Select F1, F2, year, month, pos - max(ignore_before) over win Sequence
from bordered
Window win As (partition by F1 order by year, month)
Order by
f1, year, month;
这里它运行于SQLFiddle。
因为您需要窗口位置的窗口最大值,
每个窗口函数至少需要一次通过,
因此必须使用 CTE。
请注意,我使用了窗口定义以避免重复使用(因此,避免复制错误)。