SQL 多次引用相同的递归查询 table
SQL recursive query with multiple references to same table
是否可以通过某种递归 SQL 查询 (MySQL) 而不是以编程方式解决此问题。
我有两个 table,一个包含包 ID 和名称,另一个包含包 ID 和 parent_id,它也是对其他包 ID 的引用。我需要实现的是获取包含某些特定包的包的所有 id 的列表。
下面是 tables 的示例和我正在寻找 ID 为 8 的包时所需的输出。包 8 是包 5 和 6 的一部分,但包 6 是包 1 和 4 的一部分. 所以,我需要所有这些 id 作为 array(1,4,5,6).
包table:
+----+-----------+
| 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 |
+----+-----------+
part_of table:
+----+-----------+
| id | parent_id |
+----+-----------+
| 6 | 1 |
| 6 | 4 |
| 8 | 5 |
| 8 | 6 |
+----+-----------+
输出:
+----+
| id |
+----+
| 1 |
| 4 |
| 5 |
| 6 |
+----+
编辑:更好地解释这一切是什么。这个包 table 实际上是汽车零件 table,其中还包括价格和更多字段。如果我们寻找 "timing belt" 部分,它可以是独立的,可以是某个捆绑包的一部分,我们称之为 "timing belt set" 或者可以是 "full service" 的一部分。 "timing belt"、"timing belt set"、"full service" 都存储在同一个 table 中。现在,当客户来询问 "timing belt" 时,我可以以 50 美元的价格向他提供独立服务,或以 150 美元的价格向他提供全套服务,或者我可以以 250 美元的价格提供全套服务。全部包括他要求的"timing belt"
为什么不使用 part_of table 两次?加入 table 本身的一部分 self join
然后查询 id ?我想这实际上取决于您要寻找的递归级别。
您应该可以使用 MySQL recursive common table expression:
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
table来显示每个父产品的名称:
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
| parent_id | name |
| --------- | --------- |
| 1 | package 1 |
| 4 | package 4 |
| 5 | package 5 |
| 6 | package 6 |
我写这个答案是假设您需要包 tables 来获取 ID,然后使用它从 part_of [=23] 中获取 parent_id =].这部分在你的问题中有点不清楚。如果我的假设是错误的,那么@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.
这是一个有趣的问题!
是否可以通过某种递归 SQL 查询 (MySQL) 而不是以编程方式解决此问题。
我有两个 table,一个包含包 ID 和名称,另一个包含包 ID 和 parent_id,它也是对其他包 ID 的引用。我需要实现的是获取包含某些特定包的包的所有 id 的列表。
下面是 tables 的示例和我正在寻找 ID 为 8 的包时所需的输出。包 8 是包 5 和 6 的一部分,但包 6 是包 1 和 4 的一部分. 所以,我需要所有这些 id 作为 array(1,4,5,6).
包table:
+----+-----------+
| 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 |
+----+-----------+
part_of table:
+----+-----------+
| id | parent_id |
+----+-----------+
| 6 | 1 |
| 6 | 4 |
| 8 | 5 |
| 8 | 6 |
+----+-----------+
输出:
+----+
| id |
+----+
| 1 |
| 4 |
| 5 |
| 6 |
+----+
编辑:更好地解释这一切是什么。这个包 table 实际上是汽车零件 table,其中还包括价格和更多字段。如果我们寻找 "timing belt" 部分,它可以是独立的,可以是某个捆绑包的一部分,我们称之为 "timing belt set" 或者可以是 "full service" 的一部分。 "timing belt"、"timing belt set"、"full service" 都存储在同一个 table 中。现在,当客户来询问 "timing belt" 时,我可以以 50 美元的价格向他提供独立服务,或以 150 美元的价格向他提供全套服务,或者我可以以 250 美元的价格提供全套服务。全部包括他要求的"timing belt"
为什么不使用 part_of table 两次?加入 table 本身的一部分 self join
然后查询 id ?我想这实际上取决于您要寻找的递归级别。
您应该可以使用 MySQL recursive common table expression:
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
table来显示每个父产品的名称:
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
| parent_id | name |
| --------- | --------- |
| 1 | package 1 |
| 4 | package 4 |
| 5 | package 5 |
| 6 | package 6 |
我写这个答案是假设您需要包 tables 来获取 ID,然后使用它从 part_of [=23] 中获取 parent_id =].这部分在你的问题中有点不清楚。如果我的假设是错误的,那么@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.
这是一个有趣的问题!