简体   繁体   中英

How do i find all connected nodes?

Lets say I have a table with Nodes and one table with Links that lets you create a link between two Nodes. How do I get the whole "web" of Nodes from just one Node ID? I have tried to visualize my problem like this:

在此处输入图像描述

As you can see, the Links don't form a chain like a linked list so a normal recursive query does not return all the Nodes in this web. If I start with ID 1, it will only return: 1, 2 and 3.

UPDATE : example with simple recursive query and sample data

WITH RECURSIVE links AS (
    SELECT 1 AS id_from, 2 AS id_to 
    UNION
    SELECT 2 AS id_from, 3 AS id_to 
    UNION
    SELECT 4 AS id_from, 3 AS id_to 
), web AS (
    SELECT
        l.id_from,
        l.id_to
    FROM
        links AS l
    WHERe
        id_from = 1

    UNION ALL

    SELECT
        l.id_from,
        l.id_to
    FROM
        links AS l
        jOIN web ON l.id_from = web.id_to
)

SELECT
    *
FROM
    web

OUTPUT:

id_from  |id_to
________________
      1  |     2
      2  |     3

What I would like is for the link between 4 and 3 to be included in the result.

UPDATE 2: what I am trying to achieve:

I am creating a web app without user registration. Each device is given a unique ID, but I want to make it possible to recognize a user across several devices/browsers. For this to be possible the user must be able to link their devices together. Each user will have their own cluster of device IDs like in the image above. The reason I need this query is so that I can retrieve all the devices in the cluster using any of the linked devices IDs.

Cyclic vs acyclic: I will not allow links between two nodes that are aleary apart of the cluster, will this make the graph acyclic?

Try this. I didn't test it so much, take it as a starting point:

WITH RECURSIVE links0 AS (
    SELECT 1 AS id_from, 2 AS id_to 
    UNION
    SELECT 2 AS id_from, 3 AS id_to 
    UNION
    SELECT 4 AS id_from, 3 AS id_to 
), links as (
  select id_from, id_to from links0 union select id_to, id_from from links0
), web (id_from,id_to,seen) AS (
    SELECT
        l.id_from,
        l.id_to,
        array[least(l.id_from,l.id_to)||'-'||greatest(l.id_from,l.id_to)]
    FROM
        links AS l
    WHERe
        id_from = 1

    UNION ALL

    SELECT
        l.id_from,
        l.id_to,
        web.seen || (least(l.id_from,l.id_to)||'-'||greatest(l.id_from,l.id_to))
    FROM
        links AS l
        jOIN web ON l.id_from = web.id_to
        and not (least(l.id_from,l.id_to)||'-'||greatest(l.id_from,l.id_to) = any(web.seen))
)

SELECT
    *
FROM
    web

The links CTE has edges reversed, then the seen array keeps visited edges in canonical form.

Db fiddle.

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