Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

louisph's avatar

Eloquent/SQL Recursive polymorphic (dynamic table) query

Hi,

I want to make a recursive query based on polymorphic relation. Do you know how to achieve this ?

0 likes
5 replies
louisph's avatar

Tables

sheeps

| id | eatedby_animal | eatedby_id |
| 1  | DEER           | 1          |

deers

| id | eatedby_animal | eatedby_id |
| 1  | DEER           | 2          |
| 2  | DEER           | 3          |
| 3  | GORILLA        | 1          |

gorillas

| id | eatedby_animal | eatedby_id |
| 1  | GORILLA        | 2          |
| 2  | LION           | 1          |

lions

| id | eatedby_animal | eatedby_id |
| 1  |                |            |

SQL Query

WITH RECURSIVE cte (id, eatedby_animal, eatedby_id, lvl) AS (
	SELECT
		id, eatedby_animal, eatedby_id, 0
	FROM sheeps
	WHERE id = 1
	 
	UNION ALL
	 
	SELECT
		p.id, p.eatedby_animal, p.eatedby_id, lvl - 1
	FROM gorillas AS p
	INNER JOIN cte
	 	ON cte.eatedby_animal = 'GORILLA'
	 	AND p.id = cte.eatedby_id
	 
	 UNION ALL
	 
	SELECT
		p.id, p.eatedby_animal, p.eatedby_id, lvl - 1
	FROM lions AS p
	INNER JOIN cte
		ON cte.eatedby_animal = 'LION'
		AND p.id = cte.eatedby_id

	 UNION ALL
	 
	SELECT
		p.id, p.eatedby_animal, p.eatedby_id, lvl - 1
	FROM deers AS p
	INNER JOIN cte
		ON cte.eatedby_animal = 'DEER'
		AND p.id = cte.eatedby_id
		
	 UNION ALL
	 
	SELECT
		p.id, p.eatedby_animal, p.eatedby_id, lvl - 1
	FROM sheeps AS p
	INNER JOIN cte
		ON cte.eatedby_animal = 'SHEEP'
		AND p.id = cte.eatedby_id
)

SELECT
	*
FROM cte
ORDER BY lvl ASC

OUTPUT

| eatedby_animal | eatedby_id | lvl |
| 1  |           |            | -6 |
| 2  | LION      | 1          | -5 |
| 1  | GORILLA   | 2          | -4 |
| 3  | GORILLA   | 1          | -3 |
| 2  | DEER      | 3          | -2 |
| 1  | DEER      | 2          | -1 |
| 1  | DEER      | 1          | 0  |

How to make something similar with Eloquent ?

louisph's avatar

I think it will be easier to manage if I extract the relation in a pivot table like #eatedby

| animal_type | animal_id | eatenby_type | eatenby_id | 
| SHEEP       | 1         | DEER         | 1          |
| DEER        | 1         | DEER         | 2          |
| DEER        | 2         | DEER         | 3          |
| DEER        | 3         | GORILLA      | 1          |
| GORILLA     | 1         | GORILLA      | 2          |
| GORILLA     | 2         | LION         | 1          |

Do you have some ideas how I can extract this polymorphic relation in a pivot table and make another polymorphic relation to specify the eaten animal ?

louisph's avatar

I used this pivot table and a recursive query expression to resolve the "tree".

| animal_type | animal_id | eatenby_type | eatenby_id | 
| SHEEP       | 1         | DEER         | 1          |
| DEER        | 1         | DEER         | 2          |
| DEER        | 2         | DEER         | 3          |
| DEER        | 3         | GORILLA      | 1          |
| GORILLA     | 1         | GORILLA      | 2          |
| GORILLA     | 2         | LION         | 1          |

Please or to participate in this conversation.