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

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

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

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

Данные хранятся в трех таблицах 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

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

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

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

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

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

Ответы [ 2 ]

4 голосов
/ 18 декабря 2008

Предполагая, что ваша иерархия всегда ровно на 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 для умных людей для альтернативных способов моделирования иерархии. В любом случае, это хорошая идея.

0 голосов
/ 13 января 2009

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

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

Адам.

...