按照连接:递归查询
Follow the connections : recursive query
我有两列数字。
目标从数字 f.e 开始。 55,提取所有 'connected' 个数字
(从这些数字中的任何一个开始,都应该产生相同的结果)
A B
-----
56 55
55 56
69 55
35 55
47 55
60 55
22 55
26 47
2 35
..... more data
在这种情况下,此处显示的所有数字:55,56,35,69,60,22,47,2,26
我使用以下查询:
with recursive merge as (
select A from T where A = 55 or B = 55
union
select B
from T cm join merge m
on cm.A = m.A or cm.B = m.A
)
select * from merge
但我只找回那些:55,56,35,69,60,22,47
我认为使用它会有效:
with recursive merge as (
select A from T where A = 55 or B = 55
union
(
select B
from T cm join merge m
on cm.A = m.A
union
select A
from T cm join merge m
on cm.B = m.A
)
)
select * from merge
但 Postgres 不允许在递归查询中多次使用“合并”!!?
我的目标是从数字开始,找到“链”中所有连接的数字,即
55 => 56,35,69,60,22,47 => 2,26 ....
因为 :
47 => 26
35 => 2
你可以这样做:
with recursive
n (v) as (
select case when t.a = 55 then t.b else t.a end
from t
where t.a = 55 or t.b = 55
union
select case when t.a = n.v then t.b else t.a end
from n
join t on t.a = n.v or t.b = n.v
)
select * from n
结果:
v
--
56
69
35
47
60
22
55
2
26
参见 DB Fiddle 中的 运行 示例。
或者...如果您更喜欢将参数放在一个地方:
with recursive
params as (select 55 as x), -- parameter only once
n (v) as (
select case when t.a = p.x then t.b else t.a end
from t
cross join params p
where t.a = p.x or t.b = p.x
union
select case when t.a = n.v then t.b else t.a end
from n
join t on t.a = n.v or t.b = n.v
)
select * from n
最后 UNION
编辑两个 CTE 怎么样?
WITH RECURSIVE
m1
AS
(
SELECT t.a
FROM t
WHERE a = 55
OR b = 55
UNION
SELECT t.b
FROM t
INNER JOIN m1
ON t.a = m1.a
),
m2
AS
(
SELECT t.a
FROM t
WHERE a = 55
OR b = 55
UNION
SELECT t.a
FROM t
INNER JOIN m1
ON t.b = m1.a
)
SELECT m1.a
FROM m1
UNION
SELECT m2.a
FROM m2;
这是一个无向图。因此,一种解决方案是创建所有边,然后跟随它们。
为避免无限循环,保留已访问节点的列表:
with recursive pairs as (
select a, b
from t
union -- on purpose to remove duplicates
select b, a
from t
),
cte as (
select p.a, p.b, array[p.a, p.b] as els
from pairs p
where a = 55
union all
select p.a, p.b, els || p.b
from cte join
pairs p
on cte.b = p.a
where not (p.b = any (cte.els))
)
select b
from cte;
Here 是一个 db<>fiddle.
我有两列数字。 目标从数字 f.e 开始。 55,提取所有 'connected' 个数字 (从这些数字中的任何一个开始,都应该产生相同的结果)
A B
-----
56 55
55 56
69 55
35 55
47 55
60 55
22 55
26 47
2 35
..... more data
在这种情况下,此处显示的所有数字:55,56,35,69,60,22,47,2,26
我使用以下查询:
with recursive merge as (
select A from T where A = 55 or B = 55
union
select B
from T cm join merge m
on cm.A = m.A or cm.B = m.A
)
select * from merge
但我只找回那些:55,56,35,69,60,22,47
我认为使用它会有效:
with recursive merge as (
select A from T where A = 55 or B = 55
union
(
select B
from T cm join merge m
on cm.A = m.A
union
select A
from T cm join merge m
on cm.B = m.A
)
)
select * from merge
但 Postgres 不允许在递归查询中多次使用“合并”!!?
我的目标是从数字开始,找到“链”中所有连接的数字,即
55 => 56,35,69,60,22,47 => 2,26 ....
因为 :
47 => 26
35 => 2
你可以这样做:
with recursive
n (v) as (
select case when t.a = 55 then t.b else t.a end
from t
where t.a = 55 or t.b = 55
union
select case when t.a = n.v then t.b else t.a end
from n
join t on t.a = n.v or t.b = n.v
)
select * from n
结果:
v
--
56
69
35
47
60
22
55
2
26
参见 DB Fiddle 中的 运行 示例。
或者...如果您更喜欢将参数放在一个地方:
with recursive
params as (select 55 as x), -- parameter only once
n (v) as (
select case when t.a = p.x then t.b else t.a end
from t
cross join params p
where t.a = p.x or t.b = p.x
union
select case when t.a = n.v then t.b else t.a end
from n
join t on t.a = n.v or t.b = n.v
)
select * from n
最后 UNION
编辑两个 CTE 怎么样?
WITH RECURSIVE
m1
AS
(
SELECT t.a
FROM t
WHERE a = 55
OR b = 55
UNION
SELECT t.b
FROM t
INNER JOIN m1
ON t.a = m1.a
),
m2
AS
(
SELECT t.a
FROM t
WHERE a = 55
OR b = 55
UNION
SELECT t.a
FROM t
INNER JOIN m1
ON t.b = m1.a
)
SELECT m1.a
FROM m1
UNION
SELECT m2.a
FROM m2;
这是一个无向图。因此,一种解决方案是创建所有边,然后跟随它们。
为避免无限循环,保留已访问节点的列表:
with recursive pairs as (
select a, b
from t
union -- on purpose to remove duplicates
select b, a
from t
),
cte as (
select p.a, p.b, array[p.a, p.b] as els
from pairs p
where a = 55
union all
select p.a, p.b, els || p.b
from cte join
pairs p
on cte.b = p.a
where not (p.b = any (cte.els))
)
select b
from cte;
Here 是一个 db<>fiddle.