Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 树:计算两条路径的成本,并确定哪条路径更昂贵_Sql_Postgresql_Recursion_Tree_Common Table Expression - Fatal编程技术网

Sql 树:计算两条路径的成本,并确定哪条路径更昂贵

Sql 树:计算两条路径的成本,并确定哪条路径更昂贵,sql,postgresql,recursion,tree,common-table-expression,Sql,Postgresql,Recursion,Tree,Common Table Expression,这是我在这个论坛上的第一个问题,所以我会尽量保持清晰 我有一个表实体,包含以下数据: ATTR1 ATTR2 ATTR3 ATTR4 A Level 1 null 35 B Level 2 A

这是我在这个论坛上的第一个问题,所以我会尽量保持清晰

我有一个表
实体
,包含以下数据:

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和叶节点Y(即Y是X的后代),从根到X或从X到Y的直接后代的最昂贵路径是什么
换句话说,我们假设X节点是
D
,Y节点是
p
。从节点到根的路径是
D-B-A
,而从叶到节点的路径是
P-H-D

如何计算每条路径的总成本,并能说出哪条路径更昂贵

我的方法是做2个递归查询,每个路径1个查询,以找到每个路径的总和。问题是我被迫创建了两个表,并试图将它们的所有数据放在一个表中。我觉得我已经走到了死胡同,它开始看起来有点长,不可行


非常感谢您的帮助,最好使用PostgreSQL语法。

创建如下表:

create table entity (attr1 text not null primary key,
                     attr2 text not null,
                     attr3 text,
                     attr4 int not null);
CREATE TABLE entity (
  name   text NOT NULL PRIMARY KEY
 ,level  int  NOT NULL
 ,parent text
 ,cost   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作为指定请求的一种方式有点不成熟,但我相信您可以根据需要对该部分进行修改。此外,这总是显示从“上”到“下”的路径,而不是从“外”到“内”,但我不确定这对你是否重要。无论如何,我认为这应该足够接近你想要的东西。

首先,将树的级别保存为
integer
而不是(冗余和不合适的)
文本
该表如下所示:

create table entity (attr1 text not null primary key,
                     attr2 text not null,
                     attr3 text,
                     attr4 int not null);
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;

要点
  • 提供值更快/更简单/更直观

  • 使用
    UNION ALL
    而不是
    UNION
    ,否则递归联合必须检查每个迭代是否重复(在本例中不存在)

  • 不要将
    root
    leaf
    列包含在递归CTE中,它们是自重

  • 不需要嵌套的
    WITH
    子句。您可以在带有递归
子句的
中使用普通CTE

  • 对性能最重要的是:在模型中,您事先知道路径的长度。使用它作为中断条件,不要计算所有通往痛苦终点的路径——对于大树来说,这可能非常昂贵

  • 最后的
    SELECT
    也可以大大简化,不需要聚合函数。 加入你的价值观,选择正确的路径。这样,如果需要,可以轻松显示结果中的任何或所有列


  • 难以置信!那正是我要找的!我还不熟悉递归查询,在问问题之前,我连续几个小时绞尽脑汁。答案的顺序(路径)没有区别,只要它是两条路径中代价较高的一条。多谢各位@postgresdbs:虽然Kevin的查询确实有效,但仍有很大的改进空间。我发布了一个答案。第一个非常有用的问题是+1。所有的信息都在那里,就像它应该在那里一样。