简体   繁体   English

SQL 服务器图形数据库 - 使用多种边类型的最短路径

[英]SQL Server Graph Database - shortest path using multiple edge types

I have done my research on SQL Server GraphDB, but all the contrived examples I've found so far use only a single edge table.我已经对 SQL Server GraphDB 进行了研究,但是到目前为止我发现的所有人为示例都只使用了一个边表。 It's always Person-friend_of->Person , for example.例如,它总是Person-friend_of->Person In my case, I've created a graph of deployed software components in our datacentre, and there are different edges/relationships.就我而言,我在我们的数据中心创建了一个已部署软件组件的图表,并且存在不同的边缘/关系。 Things like Application-connects_to->SqlDatabase and Server-hosts->Application .诸如Application-connects_to->SqlDatabaseServer-hosts->Application

I want to write a query that will show me the shortest path between any two nodes, regardless of the Edges used.我想编写一个查询,它将向我显示任意两个节点之间的最短路径,而不管使用的边缘如何。 I think if I was using Neo4j, I'd write the MATCH as something like:我想如果我使用的是 Neo4j,我会把MATCH写成这样:

Server-*->SqlDatabase Notice the asterisk. Server-*->SqlDatabase注意星号。

Is there an idiomatic way to do this in SQL Server?在 SQL 服务器中是否有惯用的方法来执行此操作?

Since SQL Server 2019 you can do exactly that using derived tables or views.自 SQL Server 2019 起,您可以使用派生表或视图完全做到这一点。 I couldn't find any official documentation of this feature, but i found a small remark in a video about Bill of Materials .我找不到任何有关此功能的官方文档,但我在有关材料清单的视频中发现了一个小注释。

edit: They have some links in that video: Github example编辑:他们在该视频中有一些链接: Github 示例

The point is that you use a UNION ALL of multiple EDGE (or NODE ) tables to serve as one EDGE (or NODE ) table in the MATCH operator.关键是您使用多个EDGE (或NODE )表的UNION ALL来充当MATCH运算符中的一个EDGE (或NODE )表。

  • You can use SUBSELECT您可以使用SUBSELECT
  • You can not use Common Table Expression (I couldn't make it work although I didn't try particularly hard)不能使用公用表表达式(虽然我没有特别努力,但我无法让它工作)
  • You can use View您可以使用视图

And an example:还有一个例子:

BEGIN TRANSACTION; --if you execute code found on internet without any scrutiny and have "people" table in your database
GO

  DROP TABLE IF EXISTS people, knows, killed, likes;

  CREATE TABLE people (Name VARCHAR(100)) AS NODE;
  CREATE TABLE knows AS EDGE;
  CREATE TABLE killed AS EDGE;
  CREATE TABLE likes AS EDGE;

  INSERT INTO people
    (Name)
  VALUES
    ('A'),
    ('B'),
    ('C'),
    ('D'),
    ('E')

  INSERT INTO knows
    ($from_id, $to_id)
  SELECT
    knows.$node_id, known.$node_id
  FROM
    people AS knows,
    people AS known
  WHERE
    knows.Name = 'A' AND known.Name = 'B';

  INSERT INTO killed
    ($from_id, $to_id)
  SELECT
    killed.$node_id, victim.$node_id
  FROM
    people AS killed,
    people AS victim
  WHERE
    (killed.Name = 'A' AND victim.Name = 'C')
    OR (killed.Name = 'C' AND victim.Name = 'E');

  INSERT INTO likes
    ($from_id, $to_id)
  SELECT
    likes.$node_id, liked.$node_id
  FROM
    people AS likes,
    people AS liked
  WHERE
    likes.Name = 'A' AND liked.Name = 'D';

  SELECT
    P1.Name AS First_in_chain,
    LAST_VALUE(P2.Name) WITHIN GROUP (GRAPH PATH) AS Last_in_chain
  FROM
    people AS P1,
    people FOR PATH AS P2,
    ------------------------------------------------------------------
    ---------this is a compound of edges
    (
      SELECT * FROM knows
      UNION ALL
      SELECT * FROM killed
      UNION ALL
      SELECT * FROM likes
    ) FOR PATH AS RELATION
    ------------------------------------------------------------------
  WHERE
    MATCH(
      SHORTEST_PATH(
        P1(-(RELATION)->P2)+
      )
    )
    AND P1.NAME = 'A'
  OPTION(RECOMPILE);

  DROP TABLE IF EXISTS people, knows, killed, likes;

GO
  IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM