【问题标题】:How to get all levels data using single SQL query for bill of material如何使用单个 SQL 查询获取物料清单的所有级别数据
【发布时间】:2019-08-19 13:41:28
【问题描述】:

我有很多物料清单项目,其中包含它们的原材料和半成品。半成品有自己的物料清单,包括原材料和进一步的半成品等。

我想创建一个 SQL 查询,我想通过该查询获取物料清单的详细信息直到最后一级。我将为父物料清单添加一个 WHERE 子句,并且应该将详细信息提升到最后一级。不限于7级,有些项目甚至可以达到10级或15级。

以下是层次结构的示例,例如项目“A”。

下面是表的结构和里面的数据。

【问题讨论】:

  • 这是分层 (connect by) 查询的简单应用。但输出与您显示的格式不完全一致。实际上,您显示的格式与本身不一致。 A 使用原材料 B、C、F。在前三行中,您只显示 A 一次。但在表的后面,F 使用原材料 K 和 L,并且您在 两行 行中显示 F。如果那是您想要的确切格式,您需要更好地解释它。
  • 另外,您发布了输入数据的图像(用于测试)。唯一比发布图像更糟糕的是根本不发布输入数据。更好:一个 WITH 子句,或 CREATE TABLE 和 INSERT 语句来创建数据。更糟糕(但仍然比发布图片更好):发布同一张表格,但以纯文本格式发布。 WITH 子句最简单:with test_data (bom_code, rm_code, qty) as (select 'A', 'B', 1 from dual union all select 'A', 'C', 2 from dual union all .......)

标签: sql oracle oracle11g hierarchical-data recursive-query


【解决方案1】:

使用分层查询和过滤器仅获取叶节点。

Oracle 设置

CREATE TABLE table_name ( bom_code, rm_code, qty ) AS
  SELECT 'A', 'B', 1 FROM DUAL UNION ALL
  SELECT 'A', 'C', 2 FROM DUAL UNION ALL
  SELECT 'A', 'D', 5 FROM DUAL UNION ALL
  SELECT 'A', 'E', 3 FROM DUAL UNION ALL
  SELECT 'A', 'F', 8 FROM DUAL UNION ALL
  SELECT 'D', 'G', 2 FROM DUAL UNION ALL
  SELECT 'D', 'H', 1 FROM DUAL UNION ALL
  SELECT 'D', 'I', 1 FROM DUAL UNION ALL
  SELECT 'D', 'J', 1 FROM DUAL UNION ALL
  SELECT 'F', 'K', 1 FROM DUAL UNION ALL
  SELECT 'F', 'L', 1 FROM DUAL UNION ALL
  SELECT 'G', 'Z', 1 FROM DUAL UNION ALL
  SELECT 'G', 'AA', 3 FROM DUAL UNION ALL
  SELECT 'I', 'M', 4 FROM DUAL UNION ALL
  SELECT 'I', 'N', 9 FROM DUAL UNION ALL
  SELECT 'I', 'O', 7 FROM DUAL UNION ALL
  SELECT 'N', 'P', 6 FROM DUAL UNION ALL
  SELECT 'N', 'Q', 12 FROM DUAL UNION ALL
  SELECT 'N', 'R', 4 FROM DUAL UNION ALL
  SELECT 'N', 'S', 9 FROM DUAL UNION ALL
  SELECT 'S', 'T', 3 FROM DUAL UNION ALL
  SELECT 'S', 'U', 2 FROM DUAL UNION ALL
  SELECT 'T', 'V', 1 FROM DUAL UNION ALL
  SELECT 'T', 'W', 3 FROM DUAL UNION ALL
  SELECT 'U', 'X', 5 FROM DUAL UNION ALL
  SELECT 'U', 'Y', 8 FROM DUAL;

查询

SELECT t.*,
       SYS_CONNECT_BY_PATH( BOM_CODE, '-' ) || '-' || RM_CODE AS path,
       LEVEL
FROM   table_name t
WHERE  CONNECT_BY_ISLEAF = 1
START WITH bom_code = 'A'
CONNECT BY PRIOR rm_code = bom_code;

输出

BOM_CODE | RM_CODE |数量 |路径 |等级 :------- | :-------- | --: | :------------- | ----: 一个 |乙| 1 | -A-B | 1 一个 | C | 2 | -A-C | 1 克|机管局 | 3 | -A-D-G-AA | 3 克| Z | 1 | -A-D-G-Z | 3 D | H | 1 | -A-D-H | 2 我 |中号 | 4 | -A-D-I-M | 3 N |磷 | 6 | -A-D-I-N-P | 4 N |问 | 12 | -A-D-I-N-Q | 4 N |右 | 4 | -A-D-I-N-R | 4 T |五 | 1 | -A-D-I-N-S-T-V | 6 T | W | 3 | -A-D-I-N-S-T-W | 6 你 | X | 5 | -A-D-I-N-S-U-X | 6 你 |是 | 8 | -A-D-I-N-S-U-Y | 6 我 | ○ | 7 | -A-D-I-O | 3 D | Ĵ | 1 | -A-D-J | 2 一个 | E | 3 | -A-E | 1 F | ķ | 1 | -A-F-K | 2 F |大号 | 1 | -A-F-L | 2

查询 2

如果您想要沿路径的总数,则使用相关子查询以反向遍历层次结构:

SELECT t.*,
       SYS_CONNECT_BY_PATH( BOM_CODE, '-' ) || '-' || RM_CODE AS path,
       LEVEL,
       ( SELECT SUM( qty )
         FROM   table_name s
         START WITH t.rm_code = s.rm_code
         CONNECT BY PRIOR bom_code = rm_code ) AS total_qty
FROM   table_name t
WHERE  CONNECT_BY_ISLEAF = 1
START WITH bom_code = 'A'
CONNECT BY PRIOR rm_code = bom_code;

输出

BOM_CODE | RM_CODE |数量 |路径 |水平 | TOTAL_QTY :------- | :-------- | --: | :------------- | ----: | --------: 一个 |乙| 1 | -A-B | 1 | 1 一个 | C | 2 | -A-C | 1 | 2 克|机管局 | 3 | -A-D-G-AA | 3 | 10 克| Z | 1 | -A-D-G-Z | 3 | 8 D | H | 1 | -A-D-H | 2 | 6 我 |中号 | 4 | -A-D-I-M | 3 | 10 N |磷 | 6 | -A-D-I-N-P | 4 | 21 N |问 | 12 | -A-D-I-N-Q | 4 | 27 N |右 | 4 | -A-D-I-N-R | 4 | 19 T |五 | 1 | -A-D-I-N-S-T-V | 6 | 28 T | W | 3 | -A-D-I-N-S-T-W | 6 | 30 你 | X | 5 | -A-D-I-N-S-U-X | 6 | 31 你 |是 | 8 | -A-D-I-N-S-U-Y | 6 | 34 我 | ○ | 7 | -A-D-I-O | 3 | 13 D | Ĵ | 1 | -A-D-J | 2 | 6 一个 | E | 3 | -A-E | 1 | 3 F | ķ | 1 | -A-F-K | 2 | 9 F |大号 | 1 | -A-F-L | 2 | 9

db小提琴here

【讨论】:

  • 可能还需要 ORDER BY 子句(取决于所需的确切格式)。例如,似乎 OP 总是希望首先显示叶节点,然后才显示同一父节点下的半成品。
  • @mathguy OP 可能会想要一个 ORDER SIBLINGS BY 子句而不是使用 ORDER BY 但在问题中没有提到如何排序,所以它似乎超出了答案的范围。
  • order siblings by 如果您必须通过connect_by_isleaf 订购兄弟姐妹,则将不起作用。排序可能非常混乱。至于范围:您的查询已经不会产生 OP 要求的格式的输出。不过,更有意义的是,“范围”还没有定义(显然 OP 没有发布正确和完整的问题陈述,所以我们不知道范围是什么)。在解决问题时,一个重要的步骤是与提出问题的一方来回交流,以获得清晰完整的问题陈述。在这种情况下,这还没有发生。
猜你喜欢
  • 2012-03-29
  • 2013-08-27
  • 1970-01-01
  • 2022-11-30
  • 2016-11-28
  • 2021-11-17
  • 2012-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多