sql window 每次 partionion 值改变时函数
sql window function every time partionion value changes
是否可以编写一个 window 函数,每次分区值更改时都进行分区?
例如:
create table test (id int, i int);
insert into test values (1, 1), (2, 0),(3, 0),(4, 1),(5, 1),(6, 1),(7, 0),(8, 0),(9, 1);
select
id,
i,
row_number() over (partition by i order by id asc) rn
from
test
order by
id asc;
将给我以下结果:
id i rn
----------
1 1 1
2 0 1
3 0 2
4 1 2
5 1 3
6 1 4
7 0 3
8 0 4
9 1 5
但是,我希望能够在 i
的值根据我的排序顺序更改时再次重新启动计数器,无论它是否已经出现。
例如,期望的结果是这样的:
id i rn
----------
1 1 1
2 0 1
3 0 2
4 1 1
5 1 2
6 1 3
7 0 1
8 0 2
9 1 1
同样的原则也适用于其他 window 函数,例如累计和。
我真的不想为此循环,我找不到合适的 window 函数。
谢谢
这个问题是一个缺口和孤岛问题。我从这个问题中得出了我对这个问题的解决方案:
我的查询是这样的:
with cte as (
SELECT id, i,
ROW_NUMBER() OVER (PARTITION BY i order by id) rn1
FROM test
)
SELECT id, i,
ROW_NUMBER() OVER (PARTITION BY CAST((id - rn1) as CHAR(100)) || CAST(i as CHAR(100)) ORDER BY id) rn
FROM cte
ORDER BY
id
我扩展了您的数据集以验证答案。我在 Tim Biegeleisen 的回答中使用了相同的概念。我得到 i 的行号,然后从 id 中减去它。这些差异应该导致每个具有相同 i 的 id 号的值相同,直到 i 再次切换。我 运行 在 8,0 遇到了一个问题,row_number 为 4(导致差异为 4),9,1 和 row_number 为 5(也导致差异为 4)。为了解决这种情况,我将差异转换为字符串并连接 I,形成一个我们可以分区的唯一 ID。
您可以在这个 dbfiddle 上查看:
https://www.db-fiddle.com/f/hnGUTZGLvRQ5JoSCHozAhs/0
您可以通过添加一个包含前一个 i
的列(使用 lag(i)
)来实现这一点,然后保持 运行 总的“翻转”次数“(当前 i <> 前一 i)。翻转次数相同的行属于同一组。
with u as
(select id, i, lag(i) over (order by id) as previousi
from test),
v as
(select id,
i,
sum(case when i = previousi then 0 else 1 end)
over (order by id rows unbounded preceding) as flips
from u)
select id, i, row_number() over (partition by flips order by id) as rn
from v
是否可以编写一个 window 函数,每次分区值更改时都进行分区?
例如:
create table test (id int, i int);
insert into test values (1, 1), (2, 0),(3, 0),(4, 1),(5, 1),(6, 1),(7, 0),(8, 0),(9, 1);
select
id,
i,
row_number() over (partition by i order by id asc) rn
from
test
order by
id asc;
将给我以下结果:
id i rn
----------
1 1 1
2 0 1
3 0 2
4 1 2
5 1 3
6 1 4
7 0 3
8 0 4
9 1 5
但是,我希望能够在 i
的值根据我的排序顺序更改时再次重新启动计数器,无论它是否已经出现。
例如,期望的结果是这样的:
id i rn
----------
1 1 1
2 0 1
3 0 2
4 1 1
5 1 2
6 1 3
7 0 1
8 0 2
9 1 1
同样的原则也适用于其他 window 函数,例如累计和。
我真的不想为此循环,我找不到合适的 window 函数。
谢谢
这个问题是一个缺口和孤岛问题。我从这个问题中得出了我对这个问题的解决方案:
我的查询是这样的:
with cte as (
SELECT id, i,
ROW_NUMBER() OVER (PARTITION BY i order by id) rn1
FROM test
)
SELECT id, i,
ROW_NUMBER() OVER (PARTITION BY CAST((id - rn1) as CHAR(100)) || CAST(i as CHAR(100)) ORDER BY id) rn
FROM cte
ORDER BY
id
我扩展了您的数据集以验证答案。我在 Tim Biegeleisen 的回答中使用了相同的概念。我得到 i 的行号,然后从 id 中减去它。这些差异应该导致每个具有相同 i 的 id 号的值相同,直到 i 再次切换。我 运行 在 8,0 遇到了一个问题,row_number 为 4(导致差异为 4),9,1 和 row_number 为 5(也导致差异为 4)。为了解决这种情况,我将差异转换为字符串并连接 I,形成一个我们可以分区的唯一 ID。
您可以在这个 dbfiddle 上查看: https://www.db-fiddle.com/f/hnGUTZGLvRQ5JoSCHozAhs/0
您可以通过添加一个包含前一个 i
的列(使用 lag(i)
)来实现这一点,然后保持 运行 总的“翻转”次数“(当前 i <> 前一 i)。翻转次数相同的行属于同一组。
with u as
(select id, i, lag(i) over (order by id) as previousi
from test),
v as
(select id,
i,
sum(case when i = previousi then 0 else 1 end)
over (order by id rows unbounded preceding) as flips
from u)
select id, i, row_number() over (partition by flips order by id) as rn
from v