【问题标题】:sql server graph query, find all paths to nodesql server图查询,找到节点的所有路径
【发布时间】:2020-04-25 04:24:18
【问题描述】:

我有一个非常常见的问题,我正在尝试使用图形查询(sql server 2017)来解决。

  1. 我想构建一个查询并查找节点中的任何人如何连接到C
  2. 我想构建一个查询并查找节点中的任何人如何连接到 C(有 1 个或 2 个连接)。

这是创建此图表的完整脚本:

DROP TABLE IF EXISTS Person;
CREATE TABLE Person (userName VARCHAR(100)  PRIMARY KEY) AS NODE;

INSERT INTO Person (userName) VALUES ('A'),('B'),('C'),('D'),('E'),('F'); 

DROP TABLE IF EXISTS Follow; 
CREATE TABLE Follow AS EDGE;

INSERT INTO Follow ($from_id, $to_id) VALUES (
   (SELECT $node_id FROM dbo.Person WHERE userName = 'A'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'E')),

   ((SELECT $node_id FROM dbo.Person WHERE userName = 'E'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'C')),


   ((SELECT $node_id FROM dbo.Person WHERE userName = 'C'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'A')),


   ((SELECT $node_id FROM dbo.Person WHERE userName = 'A'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'F')),

   ((SELECT $node_id FROM dbo.Person WHERE userName = 'F'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'B')),

   ((SELECT $node_id FROM dbo.Person WHERE userName = 'B'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'F')),

   ((SELECT $node_id FROM dbo.Person WHERE userName = 'B'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'E')),

   ((SELECT $node_id FROM dbo.Person WHERE userName = 'E'),
   (SELECT $node_id FROM dbo.Person WHERE userName = 'B'));

这个查询不起作用,因为它只给我直接关系:

SELECT Person1.userName as userName1, Person2.userName as userName2   
FROM Person as Person1, Follow, Person as Person2 
WHERE MATCH(Person1-(Follow)->Person2)
AND Person2.userName = 'C'

【问题讨论】:

  • 对于 sql 2017,您必须使用递归 cte。对于 sql 2019,您可以使用 satishcse 提供的答案
  • @lptr 你能分享一下如何用 cte 做吗?我有 sql 2017。非常感谢!

标签: sql-server graph sql-graph


【解决方案1】:

您可以尝试以下方法:

SELECT 
        p1.userName, 
        p1.userName as StartNode,
        LAST_VALUE(p2.userName) WITHIN GROUP (GRAPH PATH) AS FinalNode,
        STRING_AGG(p2.userName,'->') WITHIN GROUP (GRAPH PATH) AS [Edges Path],
        COUNT(p2.userName) WITHIN GROUP (GRAPH PATH) AS Levels
    FROM
        dbo.Person p1,
        dbo.Person FOR PATH p2,
        dbo.Follow FOR PATH Follow
    WHERE 
        MATCH(SHORTEST_PATH(p1(-(Follow)->p2)+))
        AND p1.userName = 'C';

要查找节点的所有传入连接,我们需要为最终节点包装查询和过滤器,如下所示:

SELECT
    username, StartNode, [Edges Path], FinalNode, Levels
FROM (
    SELECT 
        P1.username, 
        P1.username as StartNode, 
        STRING_AGG(P2.userName,'->') WITHIN GROUP (GRAPH PATH) AS [Edges Path],
        LAST_VALUE(P2.userName) WITHIN GROUP (GRAPH PATH) AS FinalNode,
        COUNT(P2.userName) WITHIN GROUP (GRAPH PATH) AS Levels
    FROM
        Person P1,
        Person FOR PATH P2,
        Follow FOR PATH Follow
    WHERE 
        MATCH(SHORTEST_PATH(P1(-(Follow)->P2)))
 ) AS Q
 WHERE Q.FinalNode = 'C'

为了限制层级或跳数,我们可以提供递归量词来代替 (+ --- one or more),如下所示:

SELECT
    username, StartNode, [Edges Path], FinalNode, Levels
FROM (
    SELECT 
        P1.username, 
        P1.username as StartNode, 
        STRING_AGG(P2.userName,'->') WITHIN GROUP (GRAPH PATH) AS [Edges Path],
        LAST_VALUE(P2.userName) WITHIN GROUP (GRAPH PATH) AS FinalNode,
        COUNT(P2.userName) WITHIN GROUP (GRAPH PATH) AS Levels
    FROM
        Person P1,
        Person FOR PATH P2,
        Follow FOR PATH Follow
    WHERE 
        MATCH(SHORTEST_PATH(P1(-(Follow)->P2){1,3}))
 ) AS Q
 WHERE Q.FinalNode = 'C'

【讨论】:

  • 谢谢您,很抱歉回复晚了。我在安装 SQL Server 2019 时遇到问题。您的查询中的任何内容都显示了所有 C 传出连接。我还想知道所有C 传入连接。例如:A->E->CF->B->E->C 可能吗?我不介意有多个查询。谢谢
  • @SexyMF 我已经更新了答案以涵盖这些场景。
  • DBFiddle 链接上面的例子:dbfiddle.uk/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多