SQL: Маркировка узлов древовидной структуры
Условие
Дана таблица tree с древовидной структурой:
CREATE TABLE tree (
node_id INT PRIMARY KEY,
parent_id INT
);
Пример данных:
| node_id | parent_id |
|---|---|
| 1 | NULL |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
Задание:
Напишите SQL-запрос, который классифицирует каждый узел:
- Root — узел без родителя (parent_id IS NULL)
- Leaf — узел без дочерних узлов
- Inner — узел с родителем и дочерними узлами
Ожидаемый результат:
| node_id | node_type |
|---|---|
| 1 | Root |
| 2 | Inner |
| 3 | Inner |
| 4 | Leaf |
| 5 | Leaf |
| 6 | Leaf |
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Задача и подход
Нужно классифицировать узлы дерева по трём типам: Root (корень), Leaf (лист), Inner (внутренний). Используем стандартные SQL техники с самоприсоединением (self-join) для определения наличия дочерних узлов и анализа родительских связей.
Основной алгоритм:
- Root: узлы где parent_id IS NULL
- Leaf: узлы, которые не появляются как parent_id для других узлов
- Inner: все остальные (имеют и родителя, и детей)
Решение на SQL
SELECT
t.node_id,
CASE
WHEN t.parent_id IS NULL THEN 'Root'
WHEN NOT EXISTS (
SELECT 1
FROM tree children
WHERE children.parent_id = t.node_id
) THEN 'Leaf'
ELSE 'Inner'
END AS node_type
FROM tree t
ORDER BY t.node_id;
Альтернативный подход с LEFT JOIN
SELECT
t.node_id,
CASE
WHEN t.parent_id IS NULL THEN 'Root'
WHEN COUNT(children.node_id) = 0 THEN 'Leaf'
ELSE 'Inner'
END AS node_type
FROM tree t
LEFT JOIN tree children ON t.node_id = children.parent_id
GROUP BY t.node_id, t.parent_id
ORDER BY t.node_id;
Объяснение логики
1. Root-узел: проверяем parent_id IS NULL — нет родителя
2. Leaf-узел: используем NOT EXISTS для проверки отсутствия дочерних узлов — если ни один узел не имеет parent_id = t.node_id, то это лист
3. Inner-узел: все остальные случаи — узлы, которые имеют и родителя, и детей
Производительность
Второй вариант с LEFT JOIN и GROUP BY часто быстрее на больших таблицах, так как использует одно сканирование вместо нескольких подзапросов. Первый вариант с NOT EXISTS может быть оптимальнее при наличии индекса на parent_id.
Результат
Для примера из условия получаем:
- node_id 1: Root (нет родителя)
- node_id 2, 3: Inner (имеют родителя и детей)
- node_id 4, 5, 6: Leaf (нет дочерних узлов)