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

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

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

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

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

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

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
3 835
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

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

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

Адам.

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