通过在一个SQL查询“链接列表”迭代?(Iterate through “linked list”

2019-09-22 13:37发布

我有一个表,基本上是这样的:

id | redirectid | data

其中redirectid是一个id到另一行。 基本上,如果一旦被选中,而且它有一个redirectid,那么redirectid数据应该在它的地方使用。 可能有多个重定向至redirectid为NULL。 从本质上讲,这些重定向形成在表中的链接列表。 我想知道的是,给定一个ID,是否有可能建立一个SQL查询,将通过所有可能的重定向循环,并在“名单”的最后返回的ID?

这是使用PostgreSQL 8.3,我想竭尽所能对SQL查询(如果可能,而不是重复在我的代码)。

Answer 1:

这是否与条款使用PostgreSQL支持递归查询? 如果是这样,这样的事情可能会奏效。 (如果你想有一个测试的答案,提供一些CREATE TABLE和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;

补充说明:

:(您可以自行基础上,与Expression实现递归我不知道顺序编程PostgreSQL的语法,所以这是一个位伪:

插入此查询到一个新表称为链接的结果:

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

同时宣布的整数::深度和其初始化为零。 然后重复以下直到它不再添加行链接。 那么链接将包含你的结果。

  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;

我认为这将是比任何光标更好的解决方案。 其实,我真的不能相信的游标会如何对这个问题非常有用的。

请注意,如果有任何周期(重定向是最终圆形的),这将不会终止。



Answer 2:

我说你应该创建一个用户定义的函数在这个脉络:

create function FindLastId (ID as integer) returns integer as $$
    declare newid integer;
    declare primaryid integer;
    declare continue boolean;
    begin
        set continue = true;
        set primaryid = $1;
        while (continue)
            select into newid redirectid from table where id = :primaryid;

            if newid is null then
                set continue = false;
            else
                set primaryid = :newid;
            end if;
        end loop;

        return primaryid;
    end;
    $$ language pgplsql;

我对Postgres的语法有点不稳,所以你可能有一些清理工作要做。 无论如何,你可以调用你的函数,如下所示:

select id, FindLastId(id) as EndId from table

在像这样的表:

id     redirectid    data
1          3          ab
2        null         cd
3          2          ef
4          1          gh
5        null         ij

这将返回:

id    EndId
1       2
2       2
3       2
4       2
5       5

请注意,这将是明显地慢,但它应该让你的ID的很快的小结果在一个很好的索引表中设置。



文章来源: Iterate through “linked list” in one SQL query?