有一个以下结构的表格:
CREATE TABLE history
(
pk serial NOT NULL,
"from" integer NOT NULL,
"to" integer NOT NULL,
entity_key text NOT NULL,
data text NOT NULL,
CONSTRAINT history_pkey PRIMARY KEY (pk)
);
pk
是主键,from
和to
定义序列中的位置以及由entity_key
标识的给定实体的序列本身。因此,如果第一行具有from = 1; to = 2
而第二行具有from = 2; to = 3
,则实体具有一行2行。所以重点是前一行的to
与下一行的from
匹配。
确定" next" /"之前"的顺序行由pk
定义,单调增长(因为它是SERIAL
)。
序列不必以1开头,to - from
不必始终为1。所以它可以是from = 1; to = 10
。重要的是" next"序列中的行与to
完全匹配。
示例数据集:
pk | from | to | entity_key | data
----+--------+------+--------------+-------
1 | 1 | 2 | 42 | foo
2 | 2 | 3 | 42 | bar
3 | 3 | 4 | 42 | baz
4 | 10 | 11 | 42 | another foo
5 | 11 | 12 | 42 | another baz
6 | 1 | 2 | 111 | one one one
7 | 2 | 3 | 111 | one one one two
8 | 3 | 4 | 111 | one one one three
而我无法实现的是如何按"序列"这里我可以将窗口函数应用于代表单个"序列"。
的组我想说我想使用row_number()
函数,并希望得到以下结果:
pk | row_number | entity_key
----+-------------+------------
1 | 1 | 42
2 | 2 | 42
3 | 3 | 42
4 | 1 | 42
5 | 2 | 42
6 | 1 | 111
7 | 2 | 111
8 | 3 | 111
为方便起见,我创建了一个带有初始种子的SQLFiddle:http://sqlfiddle.com/#!15/e7c1c
PS:它不是"给我代码"问题,我做了自己的研究,我只是想出如何分区。很明显我需要LEFT JOIN
使用next.from = curr.to
,但之后仍然不清楚如何重置next.from IS NULL
上的分区。
PS:对于提供所需结果的最优雅查询,它将获得100分赏金
PPS:由于某些其他限制超出了本问题的范围,所需的解决方案应该是SQL查询而不是pgsql。
答案 0 :(得分:7)
我不知道它是否算“优雅”,但我认为这会做你想做的事情:
with Lagged as (
select
pk,
case when lag("to",1) over (order by pk) is distinct from "from" then 1 else 0 end as starts,
entity_key
from history
), LaggedGroups as (
select
pk,
sum(starts) over (order by pk) as groups,
entity_key
from Lagged
)
select
pk,
row_number() over (
partition by groups
order by pk
) as "row_number",
entity_key
from LaggedGroups
答案 1 :(得分:2)
您可以使用generate_series()
生成两个值之间的所有行。然后你可以使用行号的差异:
select pk, "from", "to",
row_number() over (partition by entity_key, min(grp) order by pk) as row_number
from (select h.*,
(row_number() over (partition by entity_key order by ind) -
ind) as grp
from (select h.*, generate_series("from", "to" - 1) as ind
from history h
) h
) h
group by pk, "from", "to", entity_key
因为您指定差异在1到10之间,所以实际上可能没有这么糟糕的表现。
不幸的是,你的SQL Fiddle现在无法正常工作,所以我无法测试它。
答案 2 :(得分:0)
那么, 这不完全是一个 SQL查询,但是:
select a.pk as PK, a.entity_key as ENTITY_KEY, b.pk as BPK, 0 as Seq into #tmp
from history a left join history b on a."to" = b."from" and a.pk = b.pk-1
declare @seq int
select @seq = 1
update #tmp set Seq = case when (BPK is null) then @seq-1 else @seq end,
@seq = case when (BPK is null) then @seq+1 else @seq end
select pk, entity_key, ROW_NUMBER() over (PARTITION by entity_key, seq order by pk asc)
from #tmp order by pk
这是在SQL Server 2008中