SQL рекурсивный запрос с несколькими ссылками на одну таблицу - PullRequest
2 голосов
/ 27 марта 2019

Есть ли способ решить эту проблему с помощью какого-то рекурсивного SQL-запроса (MySQL) вместо того, чтобы делать это программно.

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

Ниже приведен пример таблиц и желаемого результата, если я ищу пакет с идентификатором 8. Пакет 8 является частью пакетов 5 и 6, но пакет 6 является частью пакетов 1 и 4. Итак, мне нужны все это идентификаторы как массив (1,4,5,6).

таблица пакетов:

+----+-----------+
| id | name      |
+----+-----------+
| 1  | package 1 |
| 2  | package 2 |
| 3  | package 3 |
| 4  | package 4 |
| 5  | package 5 |
| 6  | package 6 |
| 7  | package 7 |
| 8  | package 8 |
+----+-----------+

часть_ таблицы:

+----+-----------+
| id | parent_id |
+----+-----------+
| 6  |     1     |
| 6  |     4     |
| 8  |     5     |
| 8  |     6     |
+----+-----------+

выход:

+----+
| id |
+----+
| 1  |
| 4  |
| 5  |
| 6  |
+----+

РЕДАКТИРОВАТЬ: Чтобы объяснить немного лучше, о чем все это было. Эта таблица пакетов на самом деле является таблицей автомобильных запчастей, которая также включает цену и многие другие поля. Если мы ищем часть «ремня ГРМ», она может быть автономной, может быть частью какого-то комплекта, мы называем ее «комплект ремня ГРМ» или может быть частью «полного сервиса» в мастерской. Все они, «ремень ГРМ», «комплект ремня ГРМ», «полный сервис», хранятся в одной таблице. Теперь, когда клиент приходит с просьбой о «ремне ГРМ», я могу предложить ему отдельно за 50 $ или в комплекте за 150 $, или я могу предложить полный сервис за 250 $. Все они включают «ремень ГРМ», который он просил.

Ответы [ 3 ]

2 голосов
/ 27 марта 2019

Этого можно добиться, используя рекурсивное общее табличное выражение MySQL :

WITH RECURSIVE cte AS (
    SELECT id, parent_id FROM part_of WHERE id = 8
    UNION ALL
    SELECT po.id, po.parent_id FROM part_of po INNER JOIN cte ON cte.parent_id = po.id
)
SELECT parent_id FROM cte

Демонстрация на скрипте БД :

| parent_id |
| --------- |
| 5         |
| 6         |
| 1         |
| 4         |

Вы можете JOIN результаты с таблицей products, чтобы показать название каждого родительского продукта:

WITH RECURSIVE cte AS (
    SELECT id, parent_id FROM part_of WHERE id = 8
    UNION ALL
    SELECT po.id, po.parent_id FROM part_of po INNER JOIN cte ON cte.parent_id = po.id
)
SELECT cte.parent_id, p.name
FROM cte
INNER JOIN packages p on cte.parent_id = p.id

Демонстрацияна БД Fiddle :

| parent_id | name      |
| --------- | --------- |
| 1         | package 1 |
| 4         | package 4 |
| 5         | package 5 |
| 6         | package 6 |
0 голосов
/ 27 марта 2019

Я пишу этот ответ, предполагая, что вам понадобятся таблицы пакетов для получения идентификатора, который затем будет использоваться для получения parent_id из таблицы part_of. Эта часть была немного неясной в вашем вопросе. Если я ошибаюсь, предполагая это, то ответ @GBM будет работать так же хорошо, как и мой.

WITH PACKAGES_CTE AS (
    SELECT PACKAGES.ID, PACKAGES.NAME
    FROM PACKAGES
), PACKAGES2_CTE AS
    (
        SELECT *
        FROM PACKAGES2
    )

SELECT P2.PARENT_ID
FROM PACKAGES2_CTE P2
LEFT JOIN PACKAGES2_CTE P3 ON P3.PARENT_ID = P2.ID
WHERE P3.ID = 8

UNION ALL

SELECT P2.PARENT_ID
FROM PACKAGES_CTE P
LEFT JOIN PACKAGES2_CTE P2 ON P.ID = P2.ID
WHERE P2.ID = P2.PARENT_ID OR P.ID = 8

Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать. Я проверил это, используя предоставленные вами образцы данных. Поскольку я уже знал ID, мне не нужно было использовать Packages.Name. Я предполагаю, что вы захотите использовать Packages.Name = 'Package 8' вместо P.ID = 8.

Это была интересная проблема!

0 голосов
/ 27 марта 2019

Почему бы не использовать part_of table дважды? присоединиться к самой части таблицы self join и запросить идентификатор? это действительно зависит от того, какой уровень рекурсии вы ищете, я думаю.

...