2016-05-20 3 views
1

У меня есть коммерческое приложение с базой данных SQL Server 2008 R2, которая содержит таблицу, которая должна моделировать структуру файлов и папок, аналогичную < root>: < sublevel 1 >: < подуровень 2> .. < подуровень n>: < документ>. Таблица базы данных содержит пары значений (folder_item, parent), где папка - это документ или папка, а родитель - ссылка на другую строку в таблице.Рекурсивный иерархический запрос SQL Server, менее оптимальная структура данных

Я пытаюсь написать запрос, который возвращает два значения в ряд:

  • документ
  • Полный сцепленных путь к документу, из папки верхнего уровня к немедленному контейнеру документа, например Root: Level1: Level2 ..: LevelN.

Обычно рекурсивный запрос должен иметь возможность справиться с этой ситуацией, но есть осложнение. Таблица элементов папок содержит избыточные записи для каждого документа и подуровня, связывая их с каждым предком в структуре папок, а не только с их непосредственным родителем.

Вместо (документ, родитель) (родитель, бабушка или дедушка) (прародитель, пра-дедушка) ... (предок, корень)

Таблица содержит (документ, родитель) (документ, прародитель) ... (документ, предок) (документ, корень) (родитель, бабушка или дедушка) ... (родитель, предок) (родитель, корень) ... (grandparent, grand-grandparent) ... (grandparent, root)

и так далее. Я уверен, что модельеры данных имеют свои причины для разработки, но это отрицает использование стандартного рекурсивного иерархического запроса. Фактически, когда я пытался, выполнение превысило максимальное количество уровней рекурсии.

Кто-нибудь еще сталкивался с подобной проблемой и может ли она быть решена без применения сложного программирования за пределами стандартных возможностей SQL?

Спасибо большое

Патрик

+0

Как насчет отправки некоторых структур таблиц и выборочных данных? Если вы просто основываете свою рекурсию на имени, вы, вероятно, сражаетесь с проигранной битвой. –

+0

Рекурсия основана на уникальном, но не PK VARCHAR значении «DOCNUMBER», где столбец PARENT содержит DOCNUMBER строки предка. –

+0

К счастью, выяснилось, что было принято решение игнорировать существующую иерархию Папок, и проблема исчезла из-за (разумного) бизнес-решения за один раз. Спасибо Шон и Табу за ответ. –

ответ

0

Если у вас есть:

(документ, родительский) (документ, прародитель) ... (документ, предок) (документ, корень) (родитель, бабушка и дедушка) ... (родитель, предок) (родитель, корень) ... (бабушка, дедушка и бабушка) ...(Прародитель, корень)

Вы хотите ограничить рекурсию только:

(документ, родитель) (родитель, бабушка или дедушка) (прародитель, пра-дедушка) (пра-дедушка, корень)

Православие? Таким образом, трюк просто выясняет, какое условие (ы) поставить на нижнюю половину вашего рекурсивного cte, чтобы ни один из родственников текущей строки не присоединился к текущей строке.

Итак, для document, вы хотите parent. Для parent вы хотите grandparent и так далее. Как мы можем создать этот фильтр?

Ну, для document Что это такое о parent, что не относится ни к каким другим предкам?

Ответ: document имеет все одинаковые родственники, как parent, но только document имеет parent как предок.

Итак, если вы посмотрите на родителей для каждого файла folder_item, если существует другая строка, где родительский родитель такой же, как один из родителей текущего элемента, то этот файл_памят не является непосредственным родителем текущего файла folder_item и должен быть отфильтрованы из рекурсивного соединения.

Представьте себе интервью: «Итак, вы один из моих предков. Если ни один из моих других предков не будет иметь вас как предка, тогда вы должны быть моим непосредственным родителем».

Правда, не?

Я не структуру, чтобы проверить с, но я себе добавить что-то вроде этого, чтобы ваш рекурсивных присоединиться будет работать, но это, возможно, потребуется перенастройка ...

{for recursion -- Join second half of UNION back to main CTE} 
ON bottom.Folder_Item=cte.parent --you are my ancestor 
AND NOT EXISTS(
SELECT * FROM MyTable mt --others 
WHERE mt.folder_item<>bottom.folder_item --the other is not you 
AND mt.Folder_Item=cte.parent --the other is also my ancestor 
AND mt.Parent=bottom.folder_item --the other also has you as ancestor 
) 

Для этого фрагмента bottom мой псевдоним для нижней половины вашего рекурсивного UNION, а cte - это псевдоним всего CTE.

И, поместив этот фильтр в состояние JOIN для рекурсии, я думаю, что это должно помешать дереву рекурсии сходить с ума и превысить предел рекурсии. I думаю!

Если вы все еще получаете ограничение на рекурсию, попробуйте предварительно отфильтровать таблицу таким образом в CTE перед рекурсивным CTE, чтобы вы предварительно устранили всех нечеловеческих предков перед выполнением рекурсии.

Я думаю, что это должно сработать, но если нет, вы можете определенно сделать то, что вам нужно, с помощью CURSOR.

Смежные вопросы