Вернуть все узлы в иерархическом дереве «многие ко многим» - PullRequest
0 голосов
/ 08 марта 2011

Аналогично этому вопросу: Как запросить все узлы между двумя узлами в дереве?

Но у меня нет замыкания (сплющено)В таблице, у ребенка может быть много родителей, и идентификационный номер не обязательно в порядке.Глубина вложения не ограничена.

Предположим, что циклическая ссылка невозможна ... Я хотел бы вернуть все строки, необходимые для обхода иерархии.

Предположим, следующая таблица:

ParentID    ID    RowNumber(Reference)
1           2     1
2           4     2
4           3     3
3           5     4
1           6     5
6           7     6
2           8     7
3           9     8
1           8     9
6           8     10

Учитывая 1 как мне написать один запрос, чтобы вернуть все строки (получить связи всех потомков)?

Аналогично, учитывая 2 Я бы ожидал строки 2,3, 4,7,8

Учитывая 6 Я бы ожидал строки 6 и 10

Возможен случайный ложный положительный результат, как и дублированные строки в результате.Недопустимая строка недопустима

Реализация в MSAccess и SQL Server 2000 +

Ответы [ 3 ]

3 голосов
/ 08 марта 2011

Для SQL Server: Список смежных и вложенных наборов: SQL Server

Для доступа Jet / MS рекурсивные запросы не являются опцией, поэтому вложенные наборы был бы способ пойти.Для примера: http://www.mvps.org/access/queries/qry0023.htm

Некоторые сведения о вложенных наборах:

Для реализации решения с вложенными наборами вам потребуется добавить и поддерживать два дополнительных столбца в таблице: Lt и Rt (слева и справа соответственно).Вы заполняете эти столбцы, выполняя измененный обход дерева предзаказа для назначения значений этим столбцам.Это легче всего сделать с помощью рекурсивной функции.Затем вы можете использовать левое и правое значения для определения потомков во время SELECT.

Компромисс требует большей обработки при изменении данных, но намного быстрее при получении данных.

Эта концепция в некоторой степени не интуитивна и, конечно, имеет кривую обучения, но я лично использовал ее для достижения большого эффекта.Насколько я знаю, это единственный способ выполнить то, что вы делаете, после использования только запросов SELECT в Jet (механизм обработки базы данных MS Access).

Пример решения с вложенным множеством:

ParentID    ID  Lt  Rt  RowNumber(Reference)
Null        1    1  18  0
1           2    2  13  1
2           4    3  10  2
4           3    4   9  3
3           5    5   6  4
1           6   14  17  5
6           7   15  16  6
2           8   11  12  7
3           9    7   8  8

Затем, чтобы получить всех потомков идентификатора 2:

SELECT * FROM Tbl WHERE Lt Between 2 And 13

Вот как графически выглядит дерево:

Modified Preorder Tree

1 голос
/ 09 марта 2011

Поскольку необходимо моделировать данные, в которых узлы могут иметь несколько родителей, решение с вложенным набором / MPTT не будет работать.Другой альтернативой является использование таблицы закрытия .

. Вы создадите дополнительную таблицу, в которой будут храниться пары элементов для потомка каждого предка (и наоборот):

AncID  DesID
  1      2
  1      6
  1      4
  1      8
  1      7
  1      3
  1      5
  1      9
  2      4
  2      8
  2      3
  2      5
  2      9
  4      3
  4      5
  4      9
  3      5
  3      9
  6      7

Тогда вы бы использовали объединение, чтобы получить нужные вам предметы:

SELECT * 
FROM Tbl INNER JOIN Closure ON Tbl.ID=Closure.DesID 
WHERE Closure.AncID = 2
0 голосов
/ 08 марта 2011

Проверьте эту ветку, чтобы узнать, отвечает ли она на ваш вопрос с использованием ANSI SQL.По сути, у Oracle есть хороший способ сделать это с помощью предложения CONNECT BY, и вам нужно будет повторить это с помощью ANSI SQL. Моделирование ПОДКЛЮЧЕНИЯ ПО ПРИОРЕ ORACLE в СЕРВЕРЕ SQL

...