在一个 SQL 查询中迭代“链表”?

Nik*_*chi 5 sql iteration postgresql

我有一个基本上看起来像这样的表:

id | redirectid | data
Run Code Online (Sandbox Code Playgroud)

其中,redirectid 是另一行的 id。基本上,如果选择了一行,并且它有一个重定向ID,那么应该在它的位置使用重定向ID 数据。可能有多个重定向,直到redirectid 为NULL。本质上,这些重定向形成表中的链接列表。我想知道的是,给定一个 id,是否可以设置一个 sql 查询来迭代所有可能的重定向并返回“列表”末尾的 id?

这是使用 Postgresql 8.3,如果可能的话,我想在 sql 查询中完成所有操作(而不是在我的代码中迭代)。

Ste*_*ass 2

postgresql 是否支持使用WITH 子句的递归查询?如果是这样,这样的事情可能会起作用。(如果您想要经过测试的答案,请在问题中提供一些 CREATE TABLE 和 INSERT 语句,以及 INSERT 中示例数据所需的结果。)

with Links(id,link,data) as (
  select
    id, redirectid, data
  from T
  where redirectid is null
  union all
  select
    id, redirectid, null
  from T
  where redirectid is not null
  union all
  select
    Links.id,
    T.redirectid,
    case when T.redirectid is null then T.data else null end
  from T
  join Links
  on Links.link = T.id
)
  select id, data
  from Links
  where data is not null;
Run Code Online (Sandbox Code Playgroud)

附加说明:

:( 你可以根据WITH表达式自己实现递归。我不知道postgresql的顺序编程语法,所以这有点伪:

将此查询的结果插入到名为 Links 的新表中:

select
    id, redirectid as link, data, 0 as depth
  from T
  where redirectid is null
  union all
  select
    id, redirectid, null, 0
  from T
  where redirectid is not null
Run Code Online (Sandbox Code Playgroud)

还声明一个整数 ::depth 并将其初始化为零。然后重复以下操作,直到不再向链接添加行。然后链接将包含您的结果。

  increment ::depth;
  insert into Links
  select
    Links.id,
    T.redirectid,
    case when T.redirectid is null then T.data else null end,
    depth + 1
  from T join Links
  on Links.link = T.id
  where depth = ::depth-1;
end;
Run Code Online (Sandbox Code Playgroud)

我认为这比任何光标解决方案都要好。事实上,我根本无法想象游标对于这个问题有何用处。

请注意,如果存在任何循环(最终是循环的重定向),则这不会终止。