Что-то вроде следующего должно дать вам то, что вам нужно.
WITH recCTE AS
(
SELECT ID,
Parent_ID AS original_Parent_ID,
Parent_ID as next_parent_id,
NULL as ROOT_ID,
CASE WHEN Parent_ID IS NULL THEN 1 END AS is_root
FROM yourtable
UNION ALL
SELECT
reccte.id,
reccte.original_Parent_ID,
yourtable.Parent_ID,
CASE WHEN yourtable.Parent_ID IS NULL THEN reccte.next_parent_id ELSE reccte.ROOT_ID END,
NULL
FROM
recCTE
INNER JOIN yourtable ON reccte.next_parent_id = yourtable.ID
)
SELECT ID, Original_Parent_ID as Parent_ID, ROOT_ID
FROM reccte
WHERE ROOT_ID IS NOT NULL OR is_root = 1
ORDER BY ID;
В рекурсивном семени (сначала SELECT) мы собираем все записи и отмечаем, какая из них уже является root.
Затем в нашем рекурсивном термине (второй SELECT) мы идем и ищем родительскую запись для исходной записи.Если его родитель равен NULL, тогда мы заполняем столбец ROOT_ID
.
Наконец, мы ВЫБИРАЕМ из рекурсивного CTE записи, которые заполнены ROOT_ID, или записи, которые уже являются корневой записью.
В действии:
CREATE TABLE yourtable (ID int, Parent_ID int);
INSERT INTO yourtable VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 2),
(5, 4),
(6, NULL),
(7, 6);
WITH recCTE AS
(
SELECT ID,
Parent_ID AS original_Parent_ID,
Parent_ID as next_parent_id,
NULL as ROOT_ID,
CASE WHEN Parent_ID IS NULL THEN 1 END AS is_root
FROM yourtable
UNION ALL
SELECT
reccte.id,
reccte.original_Parent_ID,
yourtable.Parent_ID,
CASE WHEN yourtable.Parent_ID IS NULL THEN reccte.next_parent_id ELSE reccte.ROOT_ID END,
NULL
FROM
recCTE
INNER JOIN yourtable ON reccte.next_parent_id = yourtable.ID
)
SELECT ID, Original_Parent_ID as Parent_ID, ROOT_ID
FROM reccte
WHERE ROOT_ID IS NOT NULL OR is_root = 1
ORDER BY ID;
+----+-----------+---------+
| ID | Parent_ID | ROOT_ID |
+----+-----------+---------+
| 1 | NULL | NULL |
| 2 | 1 | 1 |
| 3 | 1 | 1 |
| 4 | 2 | 1 |
| 5 | 4 | 1 |
| 6 | NULL | NULL |
| 7 | 6 | 6 |
+----+-----------+---------+