A common model: lords have peons, and both lords and peons have things. things can be owned by one or more peons and lords. To display all things owned directly or indirectly by a lord:
SELECT lords.id AS lord_id,
peons.id AS peon_id,
things.id AS thing_id
FROM lords
LEFT JOIN lords_things ON
lords.id = lords_things.lord_id
LEFT JOIN peons ON
lords.id = peons.lord_id
LEFT JOIN peons_things ON
peons.id = peons_things.peon_id
JOIN things ON
lords_things.thing_id = things.id OR
peons_things.thing_id = things.id
WHERE lords.id = 123
Now there are two problems:
The code will have to look at which of
lord_idandpeon_idis non-NULLto determine which level the thing is connected to. There are lots of ways to solve this - For example, in Oracle you could saySELECT NVL2(things_lords.id, 'lord', 'peon') as leveland in SQL Server you should be able to say
SELECT CASE WHEN things_lords.id IS NULL THEN 'peon' ELSE 'lord' END AS levelbut I don't think either of these are portable (at least to PostgreSQL). A different approach would use a
UNION:SELECT lords.id AS owner_id, 'lord' AS level, things.id AS thing_id FROM lords JOIN lords_things ON lords.id = lords_things.lord_id JOIN things ON lords_things.thing_id = things.id WHERE lords.id = 123 UNION SELECT peons.id AS owner_id, 'peon' AS type, things.id AS thing_id FROM lords JOIN peons ON lords.id = peons.lord_id JOIN peons_things ON peons.id = peons_things.peon_id JOIN things ON peons_things.thing_id = things.id WHERE lords.id = 123this is quite ugly since it duplicates almost all the code. Is there a more elegant portable solution for this?
- Some
thingsmay show up more than once. This is not a problem in my application, but mentioned for completeness.