2017-03-16 128 views
0

所以我有了像这样的数据表公司信息:SQL递归查询的Postgres

company | role  | person 
--------|--------------|------------ 
Google | dev   | John 
Google | tester  | Bob 
Facebook| manager  | Alex 
Facebook| blah   | Bob 

我想找到通过多少个“连接” John知道的人。因此,如果约翰和鲍勃在谷歌工作约翰知道鲍勃通过1连接,但如果约翰知道鲍勃和鲍勃知道亚历克斯比约翰也知道亚历克斯延伸,但通过鲍勃意义2连接

我明白这是相当简单的图问题在代码中解决,但我一直在试图找出如何写递归SQL这样做了好几个小时,只赶上了:

WITH RECURSIVE search_graph(person, company, n) AS (
    SELECT s.person, s.company, 1 
    FROM companyinfo s 
    WHERE s.person = 'John' 
    UNION 
    SELECT s.person, s.company, n+1 
    FROM companyinfo s, search_graph sg 
    WHERE s.person = 'Alex' 
) 
SELECT * FROM search_graph limit 50; 

但它显然是行不通的,是的,它确实找到亚历克斯,但不是因为以下通过鲍勃连接和循环不忠,因此limit 50

澄清: 如果两个人在同一家公司工作,我们假设他们彼此了解。因此,该图看起来像这样:

| John | --dev-- | Google | --tester-- | Bob | --blah-- | Facebook |

这样的人和公司是节点和角色的边缘。

+0

您的表'companyinfo'没有任何关于人与人之间关系的信息。 –

+0

我应该澄清 - 在同一家公司工作过的人都认识对方 – polyx

回答

1

基本查询是找到与同一个人在同一公司工作的人,这些人在SQL中转化为companyinfo的自联接。另外,应该使用一系列的人来消除重复。

with recursive search_graph(person, persons) as (
    select s2.person, array['John'] 
    from companyinfo s1 
    join companyinfo s2 
    on s1.company = s2.company and s1.person <> s2.person 
    where s1.person = 'John' 
union 
    select s2.person, persons || s1.person 
    from companyinfo s1 
    join companyinfo s2 
    on s1.company = s2.company and s1.person <> s2.person 
    join search_graph g 
    on s1.person = g.person 
    where s1.person <> all(persons) 
) 
select distinct persons[cardinality(persons)] person, cardinality(persons) n 
from search_graph 
order by 2; 

person | n 
--------+--- 
John | 1 
Bob | 2 
Alex | 3 
(3 rows)  
+0

太棒了,但是'2 by order by'做什么? – polyx

+1

与'order by n'一样(按第二列排序)。 – klin