简体   繁体   中英

SQL Recursive query Postgres

So I have a table companyinfo that has data like so:

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

I want to find through how many "connections" does John know people. So that if John and Bob worked at Google John knows Bob through 1 connection, but if John knows Bob and Bob knows Alex than John also knows alex by extension, but through Bob meaning 2 connections

I understand this as quite simple graph problem to solve in code but I have been trying to figure out how to write recursive sql to do this for several hours and only came up with:

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;

But it obviously does not work, yes it does find Alex, but not because of following connection through bob and loops infidelity hence limit 50

Clarification: If two people worked at the same company we assume they know each other. So that graph would look something like this:

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

Such that people and companies are nodes and roles are edges.

The basic query is find people who worked in the same company with a given person which in SQL translates into self-join of companyinfo . Additionally, an array of persons should be used to eliminate repetitions.

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)    

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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