Home > Software engineering >  SQL recursion on a self-referencing table to obtain specific order
SQL recursion on a self-referencing table to obtain specific order

Time:05-20

I have a table as below:

Id LinkSlug ParentPageId Order
1 home 0
2 page2 1
3 page3 2
4 page11 1 0
5 page12 1 1
6 page13 1 2
7 page21 2 0
8 page22 2 1
9 page121 5 0
10 page122 5 1
11 page123 5 2

I'm sure you can already see the pattern - each Page can have any number of "SubPages" defined by the ParentPageId

I've been trying to get a query that can produce the following ordered output (without using the LinkSlug alphabetical ordering because they can be anything):

Id LinkSlug ParentPageId Order
1 home 0
4 page11 1 0
5 page12 1 1
9 page121 5 0
10 page122 5 1
11 page123 5 2
6 page13 1 2
2 page2 1
7 page21 2 0
8 page22 2 1
3 page3 2

I tried doing some self-joins and grouping but ended up with only one level of recursion so it was no good for the 3rd and potentially nth degree sub pages, and then also tried using a CTE as I understand they're good for recursive queries but somehow ended up producing the same table I started with and am now at a loss!

The more I try the worse it gets - I know I need to effectively select top levels (with null ParentPageId) ordered by [Order], then inject wherever there's sub pages ordering by [Order], and repeat until there are no children left - but no idea how to do this in SQL.

enter image description here

CodePudding user response:

You can try this:

WITH cte_org (n, id, 
    LinkSlug,
    ParentPageId) AS (
SELECT
    CAST([order] as CHAR(200)),
    id, 
    LinkSlug,
    ParentPageId
FROM       
    pages
WHERE ParentPageId IS NULL
UNION ALL
SELECT 
    o.n || '_' || e.[order],
    e.id,
    e.LinkSlug,
    e.ParentPageId
FROM 
    pages e
    INNER JOIN cte_org o 
        ON o.id = e.ParentPageId)

SELECT * FROM cte_org order by n;

Note: that in MS SQL you need to use concat instead of ||; in MySQL -

enter image description here

  • Related