У меня есть древовидная структура в SQLite, и я хочу, чтобы в запрос автоматически добавлялся закрывающий элемент (например, скобка в языке программирования или закрывающий тег в XML).
CREATE TABLE org(id int primary key, name text, boss int, sibling int);
INSERT INTO org VALUES(0, 'Alice', NULL, null);
INSERT INTO org VALUES(1, 'Bob', 0, null);
INSERT INTO org VALUES(2, 'Cindy', 0, 1);
INSERT INTO org VALUES(3, 'Dave', 1, 4);
INSERT INTO org VALUES(4, 'Emma', 1, null);
INSERT INTO org VALUES(5, 'Fred', 2, null);
INSERT INTO org VALUES(6, 'Gail', 2, 5);
Мой запрос на данный момент:
WITH RECURSIVE OrderedOrg(id, name, boss, SiblingOrder) AS (
SELECT id, name, boss, 0 FROM org
WHERE sibling IS NULL
UNION ALL
SELECT org.id, org.name, org.boss, OrderedOrg.SiblingOrder + 1
FROM org
JOIN OrderedOrg ON org.boss = OrderedOrg.boss
AND org.sibling = OrderedOrg.id
),
under_alice(id, name,SiblingOrder,level) AS (
select id, name,0,0 from org where id = 0
UNION ALL
SELECT OrderedOrg.id, OrderedOrg.name, OrderedOrg.SiblingOrder, under_alice.level+1
FROM OrderedOrg JOIN under_alice ON OrderedOrg.boss=under_alice.id
ORDER BY 4 DESC, 3 DESC
)
SELECT group_concat(name) FROM under_alice;
И результат:
Alice,Cindy,Gail,Fred,Bob,Dave,Emma
И ожидаемый результат:
<Alice><Cindy><Gail></Gail><Fred></Fred></Cindy><Bob><Dave></Dave><Emma></Emma></Alice>





Нам нужно обрабатывать два тега на человека, поэтому создайте виртуальную таблицу two, которую мы можем использовать для генерации двух выходных строк при объединении. Условие соединения x = 1 гарантирует, что рекурсия произойдет только после открывающего тега:
WITH RECURSIVE OrderedOrg ...,
two(x) AS (
VALUES (1), (2)
),
tree AS (
SELECT *
FROM (SELECT o.*, 0 AS level, two.x
FROM OrderedOrg AS o
CROSS JOIN two
WHERE boss IS NULL
ORDER BY x)
UNION ALL
SELECT o.id, o.name, o.boss, o.SiblingOrder, tree.level + 1, two.x
FROM tree
JOIN OrderedOrg AS o ON tree.x = 1
AND tree.id = o.boss
CROSS JOIN two
ORDER BY level DESC, SiblingOrder DESC, x
)
SELECT group_concat(CASE x
WHEN 1 THEN '<'
ELSE '</'
END || name || '>', '')
FROM tree;
Я подумал о таблице значений с двумя значениями, но не смог найти фактический запрос ... Еще раз спасибо, CL. ! Вы MVP SQL :)