|
-- Query to show, in an SQL resultset, what the tree should look like. |
|
-- Shouldn't be treated as something to use in a live environment, I don't think |
|
-- especially if you're trying to wedge this into an ORM. |
|
-- Note: This doesn't correctly handle NULL ancestors, so needs work. |
|
SELECT `n`.`id`, |
|
CONCAT(REPEAT('-', `ance`.`lvl`), `n`.`title`) AS hier, |
|
`ance`.`lvl`, |
|
`ance`.`ancestor_id`, |
|
`ance`.`descendant_id`, |
|
GROUP_CONCAT(`crumbs`.`ancestor_id`) AS `breadcrumbs` |
|
FROM `nodes` AS `n` |
|
JOIN `adjacencies` AS `ance` ON `n`.`id` = `ance`.`descendant_id` |
|
JOIN `adjacencies` AS `crumbs` ON `crumbs`.`descendant_id` = `ance`.`descendant_id` |
|
WHERE `ance`.`ancestor_id` = 1 |
|
GROUP BY `n`.`id` |
|
ORDER BY breadcrumbs ; |
|
|
|
-- get descendants of a node, including itself. |
|
-- In this example, find all children of "Node A." |
|
SELECT n.* |
|
FROM `nodes` AS `n` |
|
LEFT JOIN `adjacencies` AS `ance` ON `ance`.`descendant_id` = `n`.`id` |
|
WHERE `ance`.`ancestor_id` = 1 ; |
|
|
|
-- get descendants of a node, excluding itself. |
|
-- In this example, find all children of "Node A." |
|
SELECT n.* |
|
FROM `nodes` AS `n` |
|
LEFT JOIN `adjacencies` AS `ance` ON `ance`.`descendant_id` = `n`.`id` |
|
WHERE `ance`.`ancestor_id` = 1 |
|
AND NOT `ance`.`descendant_id` = 1 ; |
|
|
|
-- get ancestors of a node, including itself. |
|
-- In this example, find all ancestors of "Node G."SELECT `n`.* |
|
FROM `nodes` AS `n` |
|
LEFT JOIN `adjacencies` AS `ance` ON `n`.`id` = `ance`.`ancestor_id` |
|
WHERE `ance`.`descendant_id` = 7 ; |
|
|
|
|
|
-- get ancestors of a node, excluding itself |
|
-- In this example, find all ancestors of "Node G." |
|
SELECT `n`.* |
|
FROM `nodes` AS `n` |
|
LEFT JOIN `adjacencies` AS `ance` ON `n`.`id` = `ance`.`ancestor_id` |
|
WHERE `ance`.`descendant_id` = 7 |
|
AND NOT `ance`.`ancestor_id` = 7 ; |
|
|
|
-- this might do nodes to delete? not really sure yet. |
|
-- In this example, everything related to "Node D" |
|
SELECT * |
|
FROM `nodes` AS `n` |
|
LEFT JOIN `adjacencies` AS `ance` ON `n`.`id` = `ance`.`descendant_id` |
|
WHERE `ancestor_id` IN |
|
( SELECT `ancestor_id` |
|
FROM `adjacencies` |
|
WHERE `descendant_id` = 4 |
|
AND NOT `ancestor_id` = 4 ) |
|
AND `descendant_id` IN |
|
( SELECT `descendant_id` |
|
FROM `adjacencies` |
|
WHERE `ancestor_id` = 4 ) |
|
-- Note to self: can I just re-use the code for getting descendants including self? |
|
|
|
|
|
-- get all direct descendants of a node, excluding self |
|
-- Same as getting all descendants, with the additional where clause: |
|
-- AND `ance`.`lvl` = 1 |
|
-- Note: AND NOT `ance`.`descendant_id` = 1 isn't really needed here |
|
-- because that result will also have a lvl of 0 |
|
-- Note: changing `lvl` to > 1 will find all children that distance away, |
|
-- making 2 == grand-children, 3 == great grand-children, etc. |
|
SELECT n.* |
|
FROM `nodes` AS `n` |
|
LEFT JOIN `adjacencies` AS `ance` ON `ance`.`descendant_id` = `n`.`id` |
|
WHERE `ance`.`ancestor_id` = 1 |
|
AND NOT `ance`.`descendant_id` = 1 |
|
AND `ance`.`lvl` = 1; |
|
|
|
|
|
-- adding a new node |
|
-- manually is as follows: |
|
SELECT `ancestor_id`, |
|
2, |
|
`lvl`+1 AS `new_level` |
|
FROM `adjacencies` |
|
WHERE `descendant_id` = 1; |
|
-- for each result: |
|
INSERT INTO `adjacencies` (`ancestor_id`, `descendant_id`, `lvl`) VALUES (?, ?, ?); |
|
-- finally, add self. |
|
INSERT INTO `adjacencies` (`ancestor_id`, `descendant_id`, `lvl`) VALUES (2, 2, 0); |
|
|
|
-- adding a new node |
|
-- automatically is as follows: |
|
INSERT INTO `adjacencies` (`ancestor_id`, `descendant_id`, `lvl`) |
|
SELECT `ancestor_id`, |
|
2, |
|
lvl+1 |
|
FROM `adjacencies` |
|
WHERE `descendant_id` = 1 |
|
UNION ALL |
|
SELECT 2, |
|
2, |
|
0; |
|
|
|
-- finding root notes (that is, those with no ancestor) |
|
SELECT `n`.* |
|
FROM `nodes` AS `n` |
|
LEFT JOIN `adjacencies` AS `ance` ON `n`.`id` = `ance`.`descendant_id` |
|
WHERE `ance`.`ancestor_id` IS NULL |
|
AND `ance`.`lvl` = 1; |