You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Presto SQL场景下多级BOM物料总用量计算方案咨询

BOM总用量计算解决方案

针对Presto不支持递归查询的场景,以下提供两种可落地的实现方案:

方案1:Presto SQL 固定层级展开

适用场景:BOM最大层级可预估(大多数生产场景BOM层级不超过10级)

  • 实现思路:通过多层CTE自关联逐层传递用量,最终合并所有层级的计算结果
  • 示例代码:
-- 假设BOM表名为bom_table
WITH 
-- 提取顶层父件:无上级父件的物料,总用量直接取bom_qty
top_level AS (
    SELECT 
        parent_number,
        part_number,
        bom_qty,
        bom_qty AS total_bom_qty,
        1 AS bom_level
    FROM bom_table
    WHERE parent_number NOT IN (SELECT DISTINCT part_number FROM bom_table WHERE lowest_level = 'N')
),
-- 计算二级BOM用量
level_2 AS (
    SELECT 
        b.parent_number,
        b.part_number,
        b.bom_qty,
        t.total_bom_qty * b.bom_qty AS total_bom_qty,
        2 AS bom_level
    FROM bom_table b
    INNER JOIN top_level t ON b.parent_number = t.part_number
),
-- 计算三级BOM用量,以此类推直到覆盖最大层级
level_3 AS (
    SELECT 
        b.parent_number,
        b.part_number,
        b.bom_qty,
        l2.total_bom_qty * b.bom_qty AS total_bom_qty,
        3 AS bom_level
    FROM bom_table b
    INNER JOIN level_2 l2 ON b.parent_number = l2.part_number
)
-- 合并所有层级结果
SELECT * FROM top_level
UNION ALL
SELECT * FROM level_2
UNION ALL
SELECT * FROM level_3
-- 后续新增层级只需继续添加UNION ALL对应层级的CTE即可
  • 注意事项:可先测试当前使用的Presto版本是否支持递归CTE(部分高版本Presto/Trino已支持递归语法),如果支持可直接用递归CTE实现动态层级计算,无需固定层级展开。

方案2:Python 拓扑排序实现

适用场景:BOM层级不固定、层级数较多的场景

  • 实现思路:将BOM视为有向无环图,通过拓扑排序按从顶层到底层的顺序遍历节点,自动传递父件总用量到子件,子件转为父件时直接读取已计算好的总用量即可。
  • 示例代码:
import pandas as pd
from collections import defaultdict, deque

# 读取BOM数据,可替换为从数据库/数仓读取的逻辑
bom_df = pd.read_csv("bom_data.csv")

# 初始化数据结构
adjacency = defaultdict(list)  # BOM邻接表:key=父件编码,value=子件列表(子件编码, 单级用量)
in_degree = defaultdict(int)   # 节点入度,用于拓扑排序
part_is_parent = dict()        # 存储物料是否可作为父件
top_parent_qty = dict()        # 存储顶层父件的初始用量

# 遍历原始数据构建结构
for _, row in bom_df.iterrows():
    parent = row["parent_number"]
    part = row["part_number"]
    qty = row["bom_qty"]
    is_parent = row["lowest_level"] == "N"
    
    adjacency[parent].append((part, qty))
    in_degree[part] += 1
    part_is_parent[part] = is_parent
    # 记录顶层父件的初始用量
    if parent not in part_is_parent:
        top_parent_qty[parent] = qty

# 初始化拓扑队列:加入所有顶层父件
calc_queue = deque()
part_total_qty = dict()
for top_parent, init_qty in top_parent_qty.items():
    part_total_qty[top_parent] = init_qty
    calc_queue.append(top_parent)

# 遍历计算所有物料总用量
result = []
while calc_queue:
    current_parent = calc_queue.popleft()
    current_parent_total = part_total_qty[current_parent]
    # 遍历当前父件的所有子件
    for child_part, bom_qty in adjacency.get(current_parent, []):
        child_total = current_parent_total * bom_qty
        # 保存计算结果
        result.append({
            "parent_number": current_parent,
            "part_number": child_part,
            "bom_qty": bom_qty,
            "total_bom_qty": child_total
        })
        # 如果子件可作为父件,保存其总用量供后续计算使用
        if part_is_parent.get(child_part, False):
            part_total_qty[child_part] = child_total
        # 更新入度,入度为0表示当前子件的所有父件都已计算完成,加入队列
        in_degree[child_part] -= 1
        if in_degree[child_part] == 0:
            calc_queue.append(child_part)

# 输出结果
result_df = pd.DataFrame(result)
print(result_df)
  • 注意事项:可自行添加BOM循环依赖校验逻辑,避免遍历死循环。

内容的提问来源于stack exchange,提问作者Heather

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:48:00