如何创建仅由前一行值定义的行号?
How can I create row numbers defined only by the previous row's value?
这是一个以前由游标在我现在必须摆脱的非常老的 T-SQL 脚本中完成的任务。对于按日期排序的 table 中的一个人,我有一个值表示一个序列正在开始,然后继续,然后是一个新序列开始时(表示旧序列已经结束)。我无法弄清楚如何让这些序列中的每一个都有行号。几年前我在 R 代码库中有类似的东西,我使用 RLE 但这让我感到难过。我需要从中得到:
ID STATUS DATE A B
1 START 2000-01-01 1 1
1 CONTINUATION_A&B 2000-01-02 NULL NULL
1 CONTINUATION_A&B 2000-01-03 NULL NULL
1 START 2000-01-04 1 1
1 START 2000-01-05 1 1
1 CONTINUATION_A 2000-01-06 NULL NULL
1 CONTINUATION_A 2000-01-07 NULL NULL
为此:
ID STATUS DATE A B
1 START 2000-01-01 1 1
1 CONTINUATION_A&B 2000-01-02 2 2
1 CONTINUATION_A&B 2000-01-03 3 3
1 START 2000-01-04 1 1
1 START 2000-01-05 1 1
1 CONTINUATION_A 2000-01-06 2 1
1 CONTINUATION_A 2000-01-07 3 1
提前致谢。
不是答案,但对于最终回答问题很重要,而且评论时间太长(因此需要社区维基)。
我看到了这个:
in a table orderd by dates
...但我没有在问题中看到任何日期。示例数据中的日期字段在哪里?我们至少需要知道它的名字才能给你好的代码。
要深入了解的一件事是 tables 从来没有 有任何内在或自然的秩序。虽然主 key/clustered 索引或插入顺序看起来像是一个自然的 table 顺序,但有很多事情会扰乱它,除非您在代码中明确说明记录的顺序数据库可以按照它认为方便的任何顺序免费为您提供结果。也就是说,如果没有完全确定的 ORDER BY
子句,则同一查询的结果顺序可能而且确实会不时发生变化,具体取决于其他查询当前 运行 访问的内容相同的数据或哪些页面或索引已经在内存中。
这意味着我们需要能够引用 table 中的字段以强制执行所需的排序...我们需要了解该日期字段以编写正确的 SQL 语句。
with A as (
select *,
count(case when status = 'START' then 1 end) over (order by "date") as grp
from T
)
select *,
count(case when status in ('START', 'CONTINUATION_A', 'CONTINUATION_A&B') then 1 end)
over (partition by grp order by "date") as A,
count(case when status in ('START', 'CONTINUATION_A&B') then 1 end)
over (partition by grp order by "date") as B
from A;
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=225a1e37236c18fbb7bdbb76d7ad93dc
这假设计数器总是从 1 开始。如有必要,可以使用如下表达式进行调整:
min(A) over (partition by grp) - 1 /* offset for A */
min(B) over (partition by grp) - 1 /* offset for B */
这是一个以前由游标在我现在必须摆脱的非常老的 T-SQL 脚本中完成的任务。对于按日期排序的 table 中的一个人,我有一个值表示一个序列正在开始,然后继续,然后是一个新序列开始时(表示旧序列已经结束)。我无法弄清楚如何让这些序列中的每一个都有行号。几年前我在 R 代码库中有类似的东西,我使用 RLE 但这让我感到难过。我需要从中得到:
ID STATUS DATE A B
1 START 2000-01-01 1 1
1 CONTINUATION_A&B 2000-01-02 NULL NULL
1 CONTINUATION_A&B 2000-01-03 NULL NULL
1 START 2000-01-04 1 1
1 START 2000-01-05 1 1
1 CONTINUATION_A 2000-01-06 NULL NULL
1 CONTINUATION_A 2000-01-07 NULL NULL
为此:
ID STATUS DATE A B
1 START 2000-01-01 1 1
1 CONTINUATION_A&B 2000-01-02 2 2
1 CONTINUATION_A&B 2000-01-03 3 3
1 START 2000-01-04 1 1
1 START 2000-01-05 1 1
1 CONTINUATION_A 2000-01-06 2 1
1 CONTINUATION_A 2000-01-07 3 1
提前致谢。
不是答案,但对于最终回答问题很重要,而且评论时间太长(因此需要社区维基)。
我看到了这个:
in a table orderd by dates
...但我没有在问题中看到任何日期。示例数据中的日期字段在哪里?我们至少需要知道它的名字才能给你好的代码。
要深入了解的一件事是 tables 从来没有 有任何内在或自然的秩序。虽然主 key/clustered 索引或插入顺序看起来像是一个自然的 table 顺序,但有很多事情会扰乱它,除非您在代码中明确说明记录的顺序数据库可以按照它认为方便的任何顺序免费为您提供结果。也就是说,如果没有完全确定的 ORDER BY
子句,则同一查询的结果顺序可能而且确实会不时发生变化,具体取决于其他查询当前 运行 访问的内容相同的数据或哪些页面或索引已经在内存中。
这意味着我们需要能够引用 table 中的字段以强制执行所需的排序...我们需要了解该日期字段以编写正确的 SQL 语句。
with A as (
select *,
count(case when status = 'START' then 1 end) over (order by "date") as grp
from T
)
select *,
count(case when status in ('START', 'CONTINUATION_A', 'CONTINUATION_A&B') then 1 end)
over (partition by grp order by "date") as A,
count(case when status in ('START', 'CONTINUATION_A&B') then 1 end)
over (partition by grp order by "date") as B
from A;
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=225a1e37236c18fbb7bdbb76d7ad93dc
这假设计数器总是从 1 开始。如有必要,可以使用如下表达式进行调整:
min(A) over (partition by grp) - 1 /* offset for A */
min(B) over (partition by grp) - 1 /* offset for B */