简体   繁体   中英

SQL Query on recursive table

I have a to do a request on a "recursive table".

Please find below an example

ID    |    FATHER_ID    |    NAME
100   |    0            |  Human
101   |    0            |  Car
102   |    101          |  PORSCHE
103   |    101          |  AUDI
104   |    102          |  911
105   |    102          |  MACAN
106   |    103          |  A3
107   |    103          |  A5
...   |    ...          |

I would like to get something like

PARENT_NAME   |   NAME
PORSCHE       | 911
PORSCHE       | MACAN
AUDI          | A3
AUDI          | A5
...           | ...

I'm able to go to the first level with below query:

SELECT ID, FATHER_ID, NAME FROM LISTS WHERE FATHER_ID IN (SELECT ID FROM LISTS WHERE NAME = 'Car')


ID   |   FATHER_ID   |    NAME
102  | 101           | PORSCHE  
103  | 101           | AUDI

But is it possible to go to the level 2 (car model) by keeping level 1 information (the brand)?

I able to get information of level 2 with below query. But I'm losing brand name.

SELECT ID, FATHER_ID, NAME FROM LISTS WHERE FATHER_ID IN (SELECT ID FROM LISTS WHERE FATHER_ID IN (SELECT ID FROM LISTS WHERE NAME = 'Car'))

Thank you in advance

Regards

Walk the tree building a cumulative string as you go, then filter the result to keep only the deepest level

With FullTree as (
    Select ID, '' as Names, 0 as Level
    From Lists
    Where Father_ID = 0
  Union All
    Select ID, f.Names + ' | ' + c.Name as Names, f.level+1 as Level
    From Lists c inner join FullTree f on c.Father_ID = f.ID
)
Select Names from FullTree 
Where Level = (Select max(Level) From FullTree)
Order by Names

If you wish, you can trim the left part of the string to remove the initial vertical bar.

You can walk the tree in reverse, starting at the lowest level.

WITH cte AS (
    SELECT l.ID, l.FATHER_ID, l.NAME
    FROM LISTS l
    WHERE NOT EXISTS (SELECT 1
        FROM LISTS child
        WHERE child.FATHER_ID = l.ID)

    UNION ALL

    SELECT parent.ID, parent.FATHER_ID, CONCAT(parent.NAME, '|', child.NAME)
    FROM LISTS parent
    JOIN cte child ON child.FATHER_ID = l.ID
)
SELECT l.NAME
FROM cte
WHERE cte.FATHER_ID IS NULL;   -- this line removes intermediate levels

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