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

StackOverflow https://stackoverflow.com/questions/378608

  •  22-08-2019
  •  | 
  •  

Вопрос

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

Каждая подкатегория имеет набор организаций.Данная организация может быть представлена в нескольких подкатегориях.

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

Данные хранятся в трех таблицах SQL:

organizations
organization_id organization_name
1               Org A
2               Org B
3               Org C
4               Org D
5               Org E
6               Org F

categories
category_id parent_id category_name
0           NULL      Top Level Category
1           0         First Category
2           0         Second Category
3           1         Sub Category A
4           1         Sub Category B
5           1         Sub Category C
6           2         Sub Category D

organizations_categories -- Maps organizations to sub_categories
organization_id category_id
1               3
2               3
2               6
3               4
4               4
5               4
6               5
6               4
7               6
8               6

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

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

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

Я разрабатываю это решение, используя PHP и MySQL.

Спасибо за ваше время и предложения.

Это было полезно?

Решение

Предполагая, что ваша иерархия всегда имеет глубину ровно в 3 уровня:

SELECT DISTINCT
     O.organization_id,
     O.organization_name
FROM
     Categories CAT
INNER JOIN Categories SUB ON
     SUB.parent_id = CAT.category_id
INNER JOIN Category_Organizations CO ON
     CO.category_id = SUB.category_id
INNER JOIN Organizations O ON
     O.organization_id = CO.organization_id
WHERE
     CAT.category_id = @category_id

Вы можете изменить это на один уровень, чтобы разрешить вам передавать идентификатор подкатегории.Если на данный момент вы не знаете, есть ли у вас идентификатор категории или подкатегории, вы можете сделать следующее:

SELECT DISTINCT
     O.organization_id,
     O.organization_name
FROM
     Categories CAT
LEFT OUTER JOIN Categories SUB ON
     SUB.parent_id = CAT.category_id
INNER JOIN Category_Organizations CO ON
     CO.category_id IN (CAT.category_id, SUB.category_id)
INNER JOIN Organizations O ON
     O.organization_id = CO.organization_id
WHERE
     CAT.category_id = @category_id

Если ваша иерархия может иметь неизвестное количество уровней (или вы думаете, что это может произойти в будущем), то проверьте Деревья и иерархии Джо Селко в SQL для Smarties для альтернативных способов моделирования иерархии.В любом случае, вероятно, это хорошая идея - сделать это.

Другие советы

Не уверен, позволит ли это ваша модель данных, но вы можете использовать один столбец индекса и двоичное дерево, чтобы легко хранить эту информацию в одной таблице "OrganizationTree".Также имеет то преимущество, что вы используете один запрос без изменений для поиска на уровне категории, подкатегории или организации (например.дайте мне все результаты по X подкатегории)

Надеюсь, это поможет.

Адам.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top