具有对同一表的多个引用的SQL递归查询

时间:2019-03-26 21:36:17

标签: mysql sql recursive-query

是否可以通过某种递归SQL查询(MySQL)而不是通过编程的方式来解决此问题。

我有两个表,一个表包含程序包ID和名称,另一个表包含程序包ID和parent_id,parent_id也引用其他程序包的ID。我需要实现的是获取包含某些特定程序包的所有程序包ID的列表。

以下是表的示例,如果我正在寻找ID为8的包装,则需要输出。包装8是包装5和6的一部分,而包装6是包装1和4的一部分。因此,我需要所有该ids为array(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 个答案:

答案 0 :(得分:2)

您应该可以使用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

Demo on DB fiddle

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

您可以使用JOINproducts来显示结果,以显示每个父产品的名称:

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

Demo on DB Fiddle

| parent_id | name      |
| --------- | --------- |
| 1         | package 1 |
| 4         | package 4 |
| 5         | package 5 |
| 6         | package 6 |

答案 1 :(得分:0)

为什么不两次使用part_of表?加入部分表本身self join,然后查询id?我猜这真的取决于您要寻找的递归级别。

答案 2 :(得分:0)

我写这个答案是假设您将需要包表来获取ID,然后将其用于从part_of表中获取parent_id。这部分在您的问题中不清楚。如果我认为这是错误的,那么@GBM答案也将适用。

$"'{string.Join("', '", invTokens)}'"

如有任何疑问,请随时提问。我确实使用您提供的样本数据对此进行了测试。因为我已经知道ID,所以不需要使用Packages.Name。我假设您将要使用Packages.Name ='Package 8'而不是P.ID = 8。

这是一个有趣的问题!