我想知道是否有任何方法可以使用直接 SQL 来模拟图形模式匹配,或许可以借助递归 CTE。
这是使用 MATCH
Cypher-like syntax in SQL Server 的示例:
Find 2 people who are both friends with same person
SELECT Person1.name AS Friend1, Person2.name AS Friend2
FROM Person Person1, friend friend1, Person Person2,
friend friend2, Person Person0
WHERE MATCH(Person1-(friend1)->Person0<-(friend2)-Person2);
我知道这可以通过进行一堆连接来完成,但我想知道是否有另一种方法可以在这种简洁的模式中完成它,也许使用递归 CTE(无需访问 SQL-Server MATCH
子句)。
这是一个更新的示例,尽管需要执行几个步骤才能导入它:
- 产品:http://data.neo4j.com/northwind/products.csv
- 类别:http://data.neo4j.com/northwind/categories.csv
- 供应商:http://data.neo4j.com/northwind/suppliers.csv
模拟查询“每个供应商供应哪些类别的食品?”
MATCH (s:Supplier)-->(:Product)-->(c:Category)
RETURN s.companyName as Company, collect(distinct c.categoryName) as Categories
或者,如果表达得更像sql:
SELECT Company, CategoryName, Categories
FROM table
MATCH (s:Supplier)-->(:Product)-->(c:Category)
这取自 Neo4j 示例 -- https://neo4j.com/developer/guide-importing-data-and-etl/ .
基本上,我不想对所有 JOIN 进行硬编码(我知道该怎么做),而是想创建类似函数或表函数之类的东西,可以将其称为:
SELECT Field1, Field2, ...
FROM MATCH_TABLE_FUNCTION(table.field1, {'-->'|'--','<--'}, table.field2, ...})
我知道这不是一个简单的问题,但希望我们能在这里得到一些有创意的答案。
最佳答案
假设表中有这些数据:
create table #Person (id integer primary key, name varchar(50));
create table #friend (friend1 int, friend2 int, start_date date);
-- Insert into node table
insert into #Person values (1, 'Alice');
insert into #Person values (2, 'John');
insert into #Person values (3, 'Jacob');
insert into #Person values (4, 'Bob');
insert into #Person values (5, 'Dave');
insert into #Person values (6, 'Charlie');
insert into #Person values (7, 'Etan');
insert into #Person values (8, 'Fred');
insert into #Person values (9, 'Garry');
insert into #Person values (10, 'Hanna');
set dateformat ymd
-- Insert into edge table
insert into #friend (friend1, friend2, start_date) values
(1, 6, '2008-05-09'),
(2, 8, '2002-07-10'),
(2, 6, '2011-11-25'),
(2, 10, '2001-11-18'),
(3, 5, '2000-02-20'),
(3, 8, '2006-10-28'),
(4, 6, '2007-06-11'),
(4, 5, '2016-05-24'),
(4, 10, '2015-11-13'),
(5, 10, '2017-02-21'),
(5, 1, '2011-02-18'),
(5, 2, '2015-08-24'),
(6, 3, '2011-06-09'),
(6, 7, '2003-09-10'),
(6, 8, '2009-07-10'),
(7, 5, '2007-02-06'),
(7, 3, '2000-02-07'),
(8, 7, '2013-04-28'),
(9, 4, '2006-08-17'),
(9, 3, '2007-01-22'),
(9, 1, '2011-06-02'),
(9, 5, '2007-08-16'),
(10, 9, '2006-12-09')
因此,CTE 解决方案可能如下所示:
;with friendship as
(
select f1.friend1, f1.friend2 common_friend, 1 as level, 0 friend2, 0 common_friend2
from #friend f1
union all
select f1.friend1, f1.common_friend, level+1, f2.friend1, f2.friend2
from #friend f2
inner join friendship f1 on f1.common_friend = f2.friend2
where f1.level = 1
)
select p1.name AS Friend1, p2.name AS Friend2
from friendship f
inner join #Person p1 on f.friend1 = p1.id
inner join #Person p2 on f.friend2 = p2.id
where f.level = 2
您可以将其与节点/边/匹配进行比较:
CREATE TABLE dbo.Person (ID INTEGER PRIMARY KEY, name VARCHAR(50)) AS NODE;
CREATE TABLE dbo.friend (start_date DATE) AS EDGE;
INSERT INTO Person VALUES (1, 'Alice');
INSERT INTO Person VALUES (2, 'John');
INSERT INTO Person VALUES (3, 'Jacob');
INSERT INTO Person VALUES (4, 'Bob');
INSERT INTO Person VALUES (5, 'Dave');
INSERT INTO Person VALUES (6, 'Charlie');
INSERT INTO Person VALUES (7, 'Etan');
INSERT INTO Person VALUES (8, 'Fred');
INSERT INTO Person VALUES (9, 'Garry');
INSERT INTO Person VALUES (10, 'Hanna');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 1),(SELECT $node_id FROM dbo.Person WHERE ID = 6), '2008-05-09');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 2),(SELECT $node_id FROM dbo.Person WHERE ID = 8), '2002-07-10');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 2),(SELECT $node_id FROM dbo.Person WHERE ID = 6), '2011-11-25');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 2),(SELECT $node_id FROM dbo.Person WHERE ID = 10), '2001-11-18');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 3),(SELECT $node_id FROM dbo.Person WHERE ID = 5), '2000-02-20');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 3),(SELECT $node_id FROM dbo.Person WHERE ID = 8), '2006-10-28');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 4),(SELECT $node_id FROM dbo.Person WHERE ID = 6), '2007-06-11');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 4),(SELECT $node_id FROM dbo.Person WHERE ID = 5), '2016-05-24');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 4),(SELECT $node_id FROM dbo.Person WHERE ID = 10), '2015-11-13');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 5),(SELECT $node_id FROM dbo.Person WHERE ID = 10), '2017-02-21');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 5),(SELECT $node_id FROM dbo.Person WHERE ID = 1), '2011-02-18');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 5),(SELECT $node_id FROM dbo.Person WHERE ID = 2), '2015-08-24');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 6),(SELECT $node_id FROM dbo.Person WHERE ID = 3), '2011-06-09');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 6),(SELECT $node_id FROM dbo.Person WHERE ID = 7), '2003-09-10');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 6),(SELECT $node_id FROM dbo.Person WHERE ID = 8), '2009-07-10');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 7),(SELECT $node_id FROM dbo.Person WHERE ID = 5), '2007-02-06');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 7),(SELECT $node_id FROM dbo.Person WHERE ID = 3), '2000-02-07');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 8),(SELECT $node_id FROM dbo.Person WHERE ID = 7), '2013-04-28');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 9),(SELECT $node_id FROM dbo.Person WHERE ID = 4), '2006-08-17');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 9),(SELECT $node_id FROM dbo.Person WHERE ID = 3), '2007-01-22');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 9),(SELECT $node_id FROM dbo.Person WHERE ID = 1), '2011-06-02');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 9),(SELECT $node_id FROM dbo.Person WHERE ID = 5), '2007-08-16');
INSERT INTO dbo.friend VALUES ((SELECT $node_id FROM dbo.Person WHERE ID = 10),(SELECT $node_id FROM dbo.Person WHERE ID = 9), '2006-12-09');
-- Find 2 people who are both friends with same person
SELECT Person1.name AS Friend1, Person2.name AS Friend2
FROM Person Person1, friend friend1, Person Person2,
friend friend2, Person Person0
WHERE MATCH(Person1-(friend1)->Person0<-(friend2)-Person2);
关于sql - 使用标准 SQL 模拟图形查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69640594/