加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

sql – 行使递归查询会见有向图,就仿佛它是一个无向图

发布时间:2021-01-25 06:03:26 所属栏目:编程 来源:网络整理
导读:我必要您关于会见存储在数据库中的有向图的辅佐. 请思量以下有向图 1-2 2-1,3 3-1 表存储这些相关: create database test;c test;create table ownership ( parent bigint,child bigint,primary key (parent,child));insert into ownership (parent,child)
副问题[/!--empirenews.page--]

我必要您关于会见存储在数据库中的有向图的辅佐.

请思量以下有向图

1->2 
2->1,3 
3->1

表存储这些相关:

create database test;
c test;

create table ownership (
    parent bigint,child  bigint,primary key (parent,child)
);

insert into ownership (parent,child) values (1,2);
insert into ownership (parent,child) values (2,1);
insert into ownership (parent,3);
insert into ownership (parent,child) values (3,1);

我想提取从节点可达到的图形的全部半毗连边沿(即忽略偏向的毗连边沿).即,假如我从parent = 1开始,我想获得以下输出

1,2
2,1
2,3
3,1

我正在行使postgresql.

我已经修改了example on Postgres’ manual,它表明白递归查询,而且我已经调解了毗连前提以“向上”和“向下”(这样做我忽略了偏向).我的查询如下:

c test

WITH RECURSIVE graph(parent,child,path,depth,cycle) AS (
SELECT o.parent,o.child,ARRAY[ROW(o.parent,o.child)],false
    from ownership o
    where o.parent = 1
UNION ALL
SELECT 
    o.parent,path||ROW(o.parent,o.child),depth+1,ROW(o.parent,o.child) = ANY(path)
    from 
        ownership o,graph g
    where 
        (g.parent = o.child or g.child = o.parent) 
        and not cycle

)
select  g.parent,g.child,g.path,g.cycle
from
    graph g

其输出如下:

parent | child |               path                | cycle 
--------+-------+-----------------------------------+-------
      1 |     2 | {"(1,2)"}                         | f
      2 |     1 | {"(1,2)","(2,1)"}                 | f
      2 |     3 | {"(1,3)"}                 | f
      3 |     1 | {"(1,"(3,1)"}                 | f
      1 |     2 | {"(1,1)","(1,2)"}         | t
      1 |     2 | {"(1,3)",2)"}         | t
      3 |     1 | {"(1,1)"}         | f
      1 |     2 | {"(1,2)"}         | t
      2 |     3 | {"(1,3)"}         | f
      1 |     2 | {"(1,2)"} | t
      2 |     3 | {"(1,3)"} | t
      1 |     2 | {"(1,2)"} | t
      3 |     1 | {"(1,1)"} | t
(13 rows)

我有一个题目:查询多次提取沟通的边,由于它们通过差异的路径达到,我想停止这种环境.假如我将外部查询修改为

select  distinct g.parent,g.child from graph

我有所需的功效,但在WITH查询中如故存在服从低下,由于不必要的毗连已完成.
那么,有没有一种办理方案可以从一个给定的数据库中提取数据库中可达到的边沿,而不行使差异的?

我尚有另一个题目(这个题目已办理,请查察底部):正如您从输出中看到的那样,轮回仅在第二次达到节点时遏制.即我有(1,2)(2,3)(1,2).
我想在再次轮回最后一个节点之前遏制轮回,即具有(1,3).
我试图修改where前提如下

where
    (g.parent = o.child or g.child = o.parent) 
    and (ROW(o.parent,o.child) <> any(path))
    and not cycle

停止会见已会见的边沿,但它不起浸染,我无法领略为什么((ROW(o.parent,o.child)<>任何(路径))应该停止轮回再次进入轮回边沿可是不起浸染).如安在封锁轮回的节点之前遏制轮回一次?

编辑:正如danihp提议的,办理我行使的第二个题目

where
    (g.parent = o.child or g.child = o.parent) 
    and not (ROW(o.parent,o.child) = any(path))
    and not cycle

此刻输出不包括轮回.行从13变为6,但我如故有一再,以是提取全部边沿而没有一再且没有明明的首要(第一个)题目如故存在.当前输出有和不是ROW

parent | child |           path            | cycle 
--------+-------+---------------------------+-------
      1 |     2 | {"(1,2)"}                 | f
      2 |     1 | {"(1,1)"}         | f
      2 |     3 | {"(1,3)"}         | f
      3 |     1 | {"(1,1)"}         | f
      3 |     1 | {"(1,1)"} | f
      2 |     3 | {"(1,3)"} | f
(6 rows)

编辑#2 ::遵循Erwin Brandstetter的提议,我修改了我的查询,可是假如我没有错,提议的查询会提供比我更多的行(ROW较量如故存在,由于它对我来说好像更清晰,纵然我领略字符串较量会更有服从).
行使新查询,我得到20行,而我的得到6行

WITH RECURSIVE graph(parent,depth) AS (
SELECT o.parent,0
    from ownership o
    where 1 in (o.child,o.parent)
UNION ALL
SELECT 
    o.parent,depth+1
    from 
        ownership o,graph g
    where 
        g.child in (o.parent,o.child) 
        and ROW(o.parent,o.child) <> ALL(path)

)
select  g.parent,g.child from graph g

编辑3:以是,正如Erwin Brandstetter指出的那样,最后一个查询如故是错误的,而正确的查询可以在他的答复中找到.

当我宣布我的第一个查询时,我没有领略我错过了一些毗连,由于它产生在以下环境:假如我从节点3开始,db选择行(2,3)和(3,1) ).然后,查询的第一个归纳步调将从这些行中选择行(1,2),(2,1),从而穷乏应包括在个中的行(2,1).功效在观念上算法意味着((2,1)是“靠近”(3,1))

当我实行在Postgresql手册中修改示例时,我正好实行插手全部权的怙恃和孩子,但我错了没有生涯必需在每个步调中插手的图的值.

这些范例的查询好像按照起始节点天生差异的行集(即,取决于在根基步调中选择的行集).因此,我以为在根基步调中只选择包括起始节点的一行也许很有效,由于无论怎样您将得到任何其他“相邻”节点.

办理要领

可以像这样事变:
WITH RECURSIVE graph AS (
    SELECT parent,',' || parent::text || ',' || child::text || ',' AS path,0 AS depth
    FROM   ownership
    WHERE  parent = 1

    UNION ALL
    SELECT o.parent,g.path || o.child || ',g.depth + 1
    FROM   graph g
    JOIN   ownership o ON o.parent = g.child
    WHERE  g.path !~~ ('%,' || o.parent::text || ',' || o.child::text || ',%')
    )
SELECT  *
FROM    graph

你提到了机能,以是我在这个偏向长举办了优化.

首要概念:

>仅在界说的偏向上遍历图形.
>不必要列轮回,而是将其作为解除前提.少走一步.这也是直接谜底:

How can I do to stop cycles one step before the node that closes the
cycle?

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读