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

Fiddle