Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 连续序列的划分函数_Sql_Postgresql_Postgresql 9.3_Window Functions - Fatal编程技术网

Sql 连续序列的划分函数

Sql 连续序列的划分函数,sql,postgresql,postgresql-9.3,window-functions,Sql,Postgresql,Postgresql 9.3,Window Functions,有以下结构的表格: 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定义序列中的一个位置以及序列本身,该序列由实体\键标识。因此,

有以下结构的表格:

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
定义序列中的一个位置以及序列本身,该序列由
实体\键
标识。因此,如果第一行的
from=1,则实体有一个2行的序列;to=2
,第二个具有
from=2;to=3
。因此,这里的要点是前一行的
to
与下一行的
from
相匹配

确定“下一行”/“上一行”的顺序由单调增长的
pk
定义(因为它是一个
SERIAL

序列不必从1开始,并且并非总是需要从1开始。因此它可以是
from=1;to=10
。重要的是序列中的“下一行”与
完全匹配

样本数据集:

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\u 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
为了方便起见,我创建了一个带有初始种子的SQLFIDLE:

PS:这不是“给我密码”的问题,我做了自己的研究,我只是不知道如何划分

很明显,我需要使用
next.from=curr.to
左连接
,但是仍然不清楚如何重置
next.from上的分区为空

PS:对于提供请求结果的最优雅的查询,将获得100分的奖励


PPS:理想的解决方案应该是SQL查询,而不是pgsql,因为其他一些限制超出了这个问题的范围。

我不知道它是否算“优雅”,但我认为这可以满足您的要求:

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

只是为了好玩和完整:一个递归解决方案,重建(双重)记录链表。[这将不是最快的解决方案]

注意:我注释掉了升序pk条件,因为连接逻辑不需要它们

WITH RECURSIVE zzz AS (
        SELECT h0.pk
        , h0."to" AS next
        , h0.entity_key AS ek
        , 1::integer AS rnk
        FROM history h0
        WHERE NOT EXISTS (
                SELECT * FROM history nx
                WHERE nx.entity_key = h0.entity_key
                AND nx."to" = h0."from"
                -- AND nx.pk > h0.pk
                )
        UNION ALL
        SELECT h1.pk
        , h1."to" AS next
        , h1.entity_key AS ek
        , 1+zzz.rnk AS rnk
        FROM zzz
        JOIN history h1
          ON h1.entity_key = zzz.ek
                AND h1."from" = zzz.next
                -- AND h1.pk > zzz.pk
        )
SELECT * FROM zzz
ORDER BY ek,pk
        ;

您可以使用
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现在无法工作,因此我无法测试它。

好吧, 这不完全是一个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中

是的,我称之为“幼稚”解决方案,因为它所做的正是人们在纸上对给定数据集所做的。谢谢。@Gordon Linoff:“序列不必以1开头,而且to-from也不一定总是需要1。所以它可以是from=1;to=10。”是的,现在答案是:-)