Как остановить рекурсию в CTE? - PullRequest
0 голосов
/ 04 октября 2018

У меня есть таблица базы данных, которая выглядит следующим образом:

ID                                   | PredecessorID                        | Data
-------------------------------------|--------------------------------------|-----------------
43b1e103-d8c6-40f9-b031-e5d9ef18a739 | null                                 | ...
55f6951b-5ed3-46c8-9ad5-64e496cb521a | 43b1e103-d8c6-40f9-b031-e5d9ef18a739 | ...
3eaa0889-31a6-449d-a499-e4beb9e4cad1 | 55f6951b-5ed3-46c8-9ad5-64e496cb521a | ...

Я знаю, что могу использовать (рекурсивное) общее табличное выражение (CTE), чтобы получить отсортированный список моих данных:

WITH cte (ID, Data)
AS
(
  -- base case
  SELECT x.ID, x.Data
  FROM MyTable AS x
  WHERE x.PredecessorID IS NULL

  UNION ALL

  -- other cases
  SELECT x.ID, x.Data
  FROM MyTable as x
  INNER JOIN cte
    ON x.PredecessorID = cte.ID
)
SELECT * FROM cte

Хотя это работает, если я хочу получить всю таблицу, мне интересно, как получить только часть таблицы, скажем, все, от ID x до ID y.

Получить правую нижнюю границу легко (я предполагаю): просто измените критерии WHERE базового случая на идентификатор, с которого я хочу начать:

  -- base case
  SELECT x.ID, x.Data
  FROM MyTable AS x
  WHERE x.PredecessorID='...'

Но как насчет верхней границы?Как сказать CTE прекратить рекурсию после достижения записи с идентификатором y?

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

Мне просто любопытно, если бы вы могли просто изменить рекурсивную часть выбора, чтобы остановить, когда id становится y (при условии, что существует только 1 путь от x до y), подобно этому: with recursive cte (count) as ( select 1 as count union all select count + 1 from cte where count != 100 ) select * from cte;

0 голосов
/ 04 октября 2018

Поскольку вы выполняете итерацию здесь и имеете последний идентификатор cte, который он выбрал, доступным в вашем рекурсивном термине, вы можете просто отфильтровать результаты, когда последняя итерация нажала 'y'

WITH cte (ID, Data)
AS
(
  -- base case
  SELECT x.ID, x.Data
  FROM MyTable AS x
  WHERE x.PredecessorID IS NULL

  UNION ALL

  -- other cases
  SELECT x.ID, x.Data
  FROM MyTable as x
  INNER JOIN cte
    ON x.PredecessorID = cte.ID
  WHERE cte.id <> 'y'
)
SELECT * FROM cte;

Обратите внимание, что если вашx У id есть много ветвей, некоторые из которых не приводят к 'y', тогда эти ветви будут повторяться до тех пор, пока не достигнут своего естественного конца.Здесь будет преждевременно остановлена ​​только ветка, ведущая к y.

...