鉴于此ID表:
╔═══════╤═══════╗
║ tid_1 │ tid_2 ║
╠═══════╪═══════╣
║ 1 │ 2 ║
║ 1 │ 9 ║
║ 1 │ 10 ║
║ 2 │ 9 ║
║ 2 │ 10 ║
║ 3 │ 4 ║
║ 9 │ 10 ║
║ 9 │ 12 ║
║ 9 │ 14 ║
║ 12 │ 14 ║
╚═══════╧═══════╝
并假设每一行都有被认为是等价的集合的标签,我怎样才能(在PostgreSQL中)找到等价的传递集合?
换句话说,我知道方框14中的东西可以与之一起抛出 方框12中的东西;方框12中的东西与方框9中的东西;和方框9, 反过来,与第2和第1栏中的内容没有什么不同。
然后我想去分配一个新的设置ID(例如使用最小的ID) 传递组)所以我得到了
╔═══════╤═══════╗
║ tid │ sid ║
╠═══════╪═══════╣
║ 1 │ 1 ║
║ 2 │ 1 ║
║ 3 │ 3 ║
║ 4 │ 3 ║
║ 9 │ 1 ║
║ 10 │ 1 ║
║ 12 │ 1 ║
║ 14 │ 1 ║
╚═══════╧═══════╝
我已经设法达到这一点,我相信这是解决方案的一部分:
create view transitive_closure as (
with recursive containment as ( select
p1.tid_1 as tid_1,
p1.tid_2 as tid_2,
array[ p1.tid_1 ] as chain,
false as is_cyclic
from links as p1
union all
select distinct
p2.tid_1 as tid_1,
p2.tid_2 as tid_2,
tc.chain || p2.tid_1 as chain,
p2.tid_2 = any( chain ) as is_cyclic
from links as p2
join containment as tc on ( p2.tid_1 = tc.tid_2 )
)
select distinct tid_1, tid_3 as tid_2 from containment );
答案 0 :(得分:1)
是的,你非常接近你只需要检查并在你的递归查询中执行最低的tid,将递归查询的前半部分限制到根节点,在第二个中使用is_cyclic检查作为停止条件一半,最后输出tid_1和tid_2列的联合以及sid:
<强> SQL Fiddle 强>:
with recursive containment as (
select p1.tid_1 as tid_1,
p1.tid_2 as tid_2,
case when p1.tid_1 < p1.tid_2
then p1.tid_1
else p1.tid_2
end sid,
array[ p1.tid_1 ] as chain,
false as is_cyclic
from links as p1
where not exists (select 1 from links l where l.tid_2 = p1.tid_1)
union all
select p2.tid_1 as tid_1,
p2.tid_2 as tid_2,
case when tc.sid < p2.tid_1
and tc.sid < p2.tid_2
then tc.sid
when p2.tid_1 < p2.tid_2
then p2.tid_1
else p2.tid_2
end sid,
tc.chain || p2.tid_1 as chain,
p2.tid_2 = any( chain ) as is_cyclic
from links as p2
join containment as tc on ( p2.tid_1 = tc.tid_2 )
where not tc.is_cyclic
)
select tid_1, sid from containment
union
select tid_2, sid from containment
<强> Results 强>:
| tid_1 | sid |
|-------|-----|
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
| 4 | 3 |
| 9 | 1 |
| 10 | 1 |
| 12 | 1 |
| 14 | 1 |