我有一张看起来基本像这样的表:
id | redirectid | data
其中redirectid是另一行的id。基本上如果选择了一行,并且它有一个重定向,那么应该在它的位置使用重定向数据。可能存在多个重定向,直到redirectid为NULL。基本上这些重定向在表格中形成一个链表。我想知道的是,给定一个id,是否可以设置一个sql查询来迭代所有可能的重定向并返回“list”末尾的id?
这是使用Postgresql 8.3,如果可能的话,我想在sql查询中做一切(而不是在我的代码中迭代)。
答案 0 :(得分: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;
补充说明:
:(你可以根据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
同样声明一个integer :: depth并将其初始化为零。然后重复以下操作,直到它不再向Links添加行。然后链接将包含您的结果。
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;
我认为这比任何游标解决方案都要好。事实上,我根本无法想到游标将如何对这个问题有用。
请注意,如果存在任何循环(重定向最终为循环),则不会终止此操作。
答案 1 :(得分:1)
我会说你应该以这种方式创建一个user-defined function:
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。