One approach is to get each "level" with a separate query.
To get the first level, we can test for a NULL in redirect_id column to identify a "terminating" node.
To get the second level, we can use a JOIN operation to match rows that have a redirect_id that match the id from a "terminating" row (identified previously).
The third level follows the same pattern, adding another JOIN operation to return rows that redirect to a level two row.
And so on.
For example:
SELECT t1.id AS start_id
, t1.id AS terminate_id
FROM mytable t1
WHERE t1.redirect_id IS NULL
UNION ALL
SELECT t2.id
, t1.id
FROM mytable t1
JOIN mytable t2 ON t2.redirect_id = t1.id
WHERE t1.redirect_id IS NULL
UNION ALL
SELECT t3.id
, t1.id
FROM mytable t1
JOIN mytable t2 ON t2.redirect_id = t1.id
JOIN mytable t3 ON t3.redirect_id = t2.id
WHERE t1.redirect_id IS NULL
UNION ALL
SELECT t4.id
, t1.id
FROM mytable t1
JOIN mytable t2 ON t2.redirect_id = t1.id
JOIN mytable t3 ON t3.redirect_id = t2.id
JOIN mytable t4 ON t4.redirect_id = t3.id
WHERE t1.redirect_id IS NULL
The limitation of this single-query UNION ALL
approach is that it would need to be extended to a finite maximum number of levels. (This approach is not truly "recursive".)
If we needed a truly recursive approach, we could run each query separately, just adding an extra "level" for each run, following the same pattern. We'd know that we'd exhausted all possible paths when the result of a query returns no rows.
I've demonstrated the use of the UNION ALL
operator to combine the results into a single set, using a single query. (Add an ORDER BY
clause at the end of the statement if the order of the rows is important. It would also be easy to include a literal "level" column to the resultset, e.g. 1 AS level
for the first SELECT, the 2
on the second query, etc. to identify how far a node was from the termination.
MySQL doesn't support an Oracle style CONNECT BY
syntax (in Oracle, we COULD write a single query that would traverse this set and return the specified rows, an arbitrary number of levels.)
To get a truly "recursive" approach in MySQL would require multiple queries. (Note that MySQL can support "recursion" in stored procedure calls, if the server is configured to allow it.)