这是我在这个论坛上的第一个问题,所以我会尽量保持清楚。
我有1个表entity
,其中包含以下数据:
ATTR1 ATTR2 ATTR3 ATTR4
A Level 1 null 35
B Level 2 A 34
C Level 2 A 33
D Level 3 B 32
E Level 3 B 31
F Level 3 C 30
G Level 3 C 29
H Level 4 D 28
I Level 4 D 27
J Level 4 E 26
K Level 4 E 25
L Level 4 F 24
M Level 4 F 23
N Level 4 G 22
O Level 4 G 21
P Level 5 H 20
Q Level 5 H 19
R Level 5 H 18
S Level 5 O 17
其中ATTR1
是节点的名称。它也是主要的关键
其中ATTR2
是节点的级别
其中ATTR3
是节点父节点的名称。 A
是根,它没有父节点,因此NULL
其中ATTR4
是节点的成本。
现在的问题是:
换句话说,假设X节点为D
,Y节点为P
。从节点到根的路径为D-B-A
,而从叶到节点的路径为P-H-D
。
如何计算每条路径的总成本并且能够说哪个更昂贵?
我的方法是做2个递归查询,每个路径有1个查询来查找每个查询的SUM。问题是我被迫创建了2个表并尝试将所有数据都放在1中。我觉得我已经走到了尽头,它开始看起来有点长而且不可行。
感谢任何帮助,最好是PostgreSQL语法。
答案 0 :(得分:2)
创建这样的表:
create table entity (attr1 text not null primary key,
attr2 text not null,
attr3 text,
attr4 int not null);
...并用上面显示的数据填充它,你在找这样的东西吗?:
with recursive cst as (
with req as (
select 'A'::text as top, 'D'::text as bottom
union all
select 'D'::text, 'P'::text
)
select
top,
bottom,
top as last,
top as path,
attr4 as cost
from req
join entity on (top = attr1)
union
select
top,
bottom,
attr1,
path || '-' || attr1,
cost + attr4
from cst
join entity on (attr3 = last)
), res as (
select * from cst where bottom = last
)
select path from res
where cost = (select max(cost) from res);
当然,req
CTE作为一种指定请求的方式是一种破解,但我相信你可以按照你想要的那样完成那部分。此外,这总是显示从“上部”到“下部”而不是“外部”到“内部”的路径,但我不确定这对您来说是否重要。无论如何,我认为这应该足够接近你想要的东西。
答案 1 :(得分:0)
首先,将树的级别保存为integer
而不是(冗余且不合适)text
。
该表如下所示:
CREATE TABLE entity (
name text NOT NULL PRIMARY KEY
,level int NOT NULL
,parent text
,cost int NOT NULL);
查询:
WITH RECURSIVE val(root, leaf) AS (
VALUES -- provide values here
('A'::text, 'D'::text)
,('D', 'P')
), x AS (
SELECT v.root AS name
,v.root AS path
,r.cost AS total
,1 AS path_len
,l.level - r.level AS len -- as break condition
FROM val v
JOIN entity r ON r.name = root
JOIN entity l ON l.name = leaf
UNION ALL
SELECT e.name -- AS parent
,x.path || '-' || e.name -- AS path
,x.total + e.cost -- AS total
,x.path_len + 1 -- AS path_len
,x.len -- AS len
FROM x
JOIN entity e ON e.parent = x.name
WHERE x.path_len <= x.len
)
SELECT x.path, x.total
FROM x
JOIN val v ON x.name = v.leaf AND x.path_len > 1
ORDER BY x.total DESC
LIMIT 1;
结果:
path | total
------+-------
A-B-D | 101
VALUES
提供价值更快/更简单/更直观。
使用UNION ALL
代替UNION
,否则递归联合必须检查(在这种情况下不存在)每次迭代重复。
不要在递归CTE中包含root
和leaf
列,它们是自重的。
不需要嵌套的WITH
子句。您可以在WITH RECURSIVE
子句中使用普通CTE。
对性能最重要的是:在你的模型中,你事先知道路径的长度。使用它作为中断条件并且不计算所有到苦味末端的路径 - 对于大树来说可能非常昂贵。
最终的SELECT
也可以在很大程度上简化,不需要聚合函数。
加入您的价值观并选择正确的道路。这样,您可以根据需要轻松显示结果中的任何或所有列。