Slavenin999
@Slavenin999
программист php/erlang/elixir/js

[Mssql2012] Как правильно составить рекурсивное выражение?

Всем привет!
Есть таблица с данными, нужно построить рекурсивный запрос, который будет эти данные выбирать, как дерево. Проблема в том, что дочерний элемент может ссылаться сам на себя, что приводит к бесконечной рекурсии.
Пример
declare @t table(eNum FLOAT, dNum NVARCHAR(10), tNum FLOAT)
insert into @t values
(1.1,	'1.1.1',1.2),
(1.2,	'1.2.1',2.1),
(1.3,	'1.3.3',(null)),
(1.3,	'1.3.12',(NULL)),
(1.3,	'1.3.11',(null)),
(1.3,	'1.3.15',(null)),
(1.3,	'1.3.8',(null)),
(1.3,	'1.3.2',(null)),
(1.3,	'1.3.13',(null)),
(1.3,	'1.3.14',(null)),
(1.3,	'1.3.7',(null)),
(1.3,	'1.3.9',(null)),
(1.3,	'1.3.5',(null)),
(1.3,	'1.3.6',(null)),
(1.3,	'1.3.10',(null)),
(1.3,	'1.3.1',(null)),
(1.3,	'1.3.4',(null)),
(2.1,	'2.1.4',2.2),
(2.1,	'2.1.3',2.2),
(2.1,	'2.1.1',2.2),
(2.1,	'2.1.6',2.2),
(2.1,	'2.1.2',2.2),
(2.1,	'2.1.7',2.2),
(2.1,	'2.1.5',2.1); --если убрать эту строку, то всё работает

WITH allSteps AS (
  SELECT * FROM @t --тут запрос на получение данных из нескольких таблиц
),
AlgoSteps AS (
  SELECT alst.eNum, alst.dNum, alst.tNum, 1 AS level
    FROM allSteps AS alst 
  WHERE alst.eNum = 1.1

  UNION ALL

  SELECT alst.eNum, alst.dNum, alst.tNum, als.level + 1
    FROM allSteps AS alst 
    INNER JOIN AlgoSteps AS als ON alst.eNum = als.tNum
  WHERE alst.eNum <> 1.1

)
  SELECT * FROM AlgoSteps ORDER BY eNum, dNum
  OPTION (MAXRECURSION 5);


Каким образом можно проверить, что элемент уже есть в выборке и проигнорировать его? Пробовал
WHERE alst.eNum <> 1.1 AND NOT EXISTS (SELECT 1 FROM AlgoSteps s WHERE s.eNum = alst.eNum)

но получил ошибку:
Рекурсивный элемент обобщенного табличного выражения "AlgoSteps" имеет множественные рекурсивные ссылки.
  • Вопрос задан
  • 256 просмотров
Пригласить эксперта
Ответы на вопрос 1
tsklab
@tsklab Куратор тега SQL Server
Здесь отвечаю на вопросы.
данные выбирать, как дерево
Кроме прочих вариантов я использую такой трюк: создаю временную таблицу — список узлов. Делаю из неё курсор. Далее перебираю по порядку, добавляя для каждого узла дочерние в конец этой таблицы. В результате имеем полный список.

Уточнение:
если убрать эту строку, то всё работает
"Дерево" не должно иметь ссылки узла на самого себя.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы