Я думаю, что у меня есть формат рекурсивных CTE, достаточно хорошо, чтобы написать его, но все же считаю, что я разочарован тем, что я не могу его вручную обработать (притворись, что я сам SQL-движок, и дойду до набора результатов с помощью пера и бумага). Я нашел это, что близко к тому, что я ищу, но недостаточно подробно. У меня нет проблем отслеживать рекурсивную функцию С++ и понимать, как она работает, но для SQL я не понимаю, почему и как движок знает, что нужно остановить. Является ли привязка и рекурсивный блок вызываться каждый раз, или якорь пропущен в последующих итерациях? (Я сомневаюсь в этом, но я пытаюсь выразить свое замешательство в том, как он, кажется, прыгает.) Если якорь вызывается каждый раз, как якорь не появляется несколько раз в конечном результате? Я надеюсь, что кто-то может просто пробить линию 1 линии 2 и т.д., Что произойдет, а что "в памяти" по мере накопления результирующего набора.
Я взял на себя смелость украсть мой пример с этой страницы, так как это кажется самым легким для понимания.
DECLARE @tbl TABLE (
Id INT
, [Name] VARCHAR(20)
, ParentId INT
)
INSERT INTO @tbl( Id, Name, ParentId )
VALUES
(1, 'Europe', NULL)
,(2, 'Asia', NULL)
,(3, 'Germany', 1)
,(4, 'UK', 1)
,(5, 'China', 2)
,(6, 'India', 2)
,(7, 'Scotland', 4)
,(8, 'Edinburgh', 7)
,(9, 'Leith', 8)
;
WITH abcd
AS (
-- anchor
SELECT id, Name, ParentID,
CAST(Name AS VARCHAR(1000)) AS Path
FROM @tbl
WHERE ParentId IS NULL
UNION ALL
--recursive member
SELECT t.id, t.Name, t.ParentID,
CAST((a.path + '/' + t.Name) AS VARCHAR(1000)) AS "Path"
FROM @tbl AS t
JOIN abcd AS a
ON t.ParentId = a.id
)
SELECT * FROM abcd