EP024 PQ、PP、CUBE函数综合实战案例:制造业BOM展开卷算(上)

=List.Count(Text.Split(Text.From([BOM层级]), "."))

我们先用一句话总结这行代码的最终目的:它根据现有的【BOM层级】列(比如“1.2.1”),计算出这是第几层BOM(3层),并把结果放在一个新列【BOM层级数】里。

现在,我们把这个公式当成一个洋葱,从最外层(宏观动作)一层一层剥到最内层(核心数据),看看它是怎么运作的。


🧅 第一层:最外层的壳 —— 添加新列

= Table.AddColumn(更改的类型, "BOM层级数", ...)

  • Table.AddColumn:这是Power Query中的基础函数,意思是“给表格添加一列”。
  • 更改的类型:这是上一个步骤的名字(代表当前的表格)。
  • "BOM层级数":这是你要添加的新列的名字。
  • ...:这里面装的是新列到底要填什么数据的“计算规则”。

剥开第一层我们知道了:我们在现有的表上加了一个叫“BOM层级数”的新列。


🧅 第二层:遍历每一行 —— 启动引擎

each ...

  • each:意思是“对于表格中的每一行,都去执行后面的动作”。这是一个循环遍历的指令。

剥开第二层我们知道了:接下来的计算不是算一次,而是表格有100行,它就会一行一行地计算100次。


🧅 第三层:计算数量 —— 最终的结果

List.Count(...)

  • List.Count:意思是“数一数这个列表(List)里一共包含了几个项目”。
  • 比如列表是 {A, B, C},它算出来的结果就是 3。这个 3 就是最终填入单元格里的数字。

剥开第三层我们知道了:新列里的数字,是靠数一个“列表”里的项目数量得来的。那这个列表是怎么来的呢?继续往下剥。


🧅 第四层:按符号拆分 —— 制造列表

Text.Split(..., ".")

  • Text.Split:意思是“把一段文本,按照指定的符号切开”。
  • 这里的指定符号是 "."(英文句号)。
  • 比如,如果你给它一段文本 "1.2.1",它就会沿着小数点切两刀,变成三个部分,并打包成一个列表:{"1", "2", "1"}

剥开第四层我们知道了:刚才第三层去数的那个“列表”,是把文本按点号 . 拆分后产生的。那这段文本从哪来?到了最核心的部分了。


🧅 第五层:洋葱核心 —— 获取并转换数据

Text.From([BOM层级])

  • [BOM层级]:这代表当前这一行里,已有列【BOM层级】里的真实数据(比如 1.2.1)。
  • Text.From:意思是“把它变成文本格式”。这一步非常严谨,因为有时候系统可能会把数字或者混合格式识别错,加上 Text.From 可以确保它绝对是字符串,这样外层的 Text.Split 才不会报错。

剥到了核心我们知道了:所有的一切操作,都是基于当前行的【BOM层级】这个值开始的。


🔄 总结:数据流水的“反向”演示

既然洋葱剥完了,我们顺着数据的流向(从内到外),拿一个具体的例子 “1.2.1.4” 走一遍流水线,你会觉得无比清晰:

  1. 第五层(取值):拿到数据 1.2.1.4,确保它是文本 "1.2.1.4"
  2. 第四层(拆分):用 Text.Split 按照 . 切开它,变成一个列表 {"1", "2", "1", "4"}
  3. 第三层(计数):用 List.Count 数一数,这个列表里有 4 个元素。
  4. 第二层(循环)each 确保每一行都这么干。
  5. 第一层(成列)Table.AddColumn 把算出来的 4,填进新列【BOM层级数】对应的格子里。

这就是这行代码的全部魔法!

if [BOM层级] = "0" then null else if List.Count(Text.Split(Text.From([BOM层级]), ".")) = 2 then "0" else Text.BeforeDelimiter(Text.From([BOM层级]), ".", {0, RelativePosition.FromEnd})

咱们把这个公式像“剥洋葱”一样,一层一层剥开,看看它的“芯”里到底在想什么。

这是为了解决制造业最头疼的“跳级BOM”(即:表里有 0 级和 1.1 级,但偏偏没有 1 级)而设计的。

第一层:排除“祖宗” (0级成品)

if [BOM层级] = "0" then null

  • 业务逻辑:成品就是最高级了,它没有爸爸。
  • 动作:如果这一行是 0,它的“父级层级”直接留空(null)。

第二层:处理“一级子件” (比如 1.1, 1.2)

else if List.Count(Text.Split(Text.From([BOM层级]), ".")) = 2 then "0"

  • 剥开细节
    • Text.From([BOM层级]):先把数据转成文本(防止系统把 1.10 当成 1.1)。
    • Text.Split(..., "."):按点切开。比如 1.1 被切成了 {"1", "1"} 两个部分。
    • List.Count(...) = 2:数一数,如果切开后正好是两段,说明它就是成品的直接下属。
  • 业务逻辑:既然它是 1.1 这种结构,虽然中间没写 1,但它的亲生父亲一定是 0
  • 动作:强制把它的父级设为 0

第三层:处理“深层零件” (比如 1.1.1, 1.1.2.1)

else Text.BeforeDelimiter(Text.From([BOM层级]), ".", {0, RelativePosition.FromEnd})

  • 剥开细节
    • Text.BeforeDelimiter:意思是“取某个分隔符之前的内容”。
    • RelativePosition.FromEnd:这是点睛之笔!意思是“从右往左数,找到第一个点”
  • 举例
    • 如果是 1.1.1,从右边数第一个点在第二个 1 前面,截取之后得到 1.1
    • 如果是 1.1.2.1,从右边数第一个点在末尾的 1 前面,截取得到 1.1.2
  • 业务逻辑:不管你有多少层,只要把最后一段掐掉,剩下的就是你亲爹。

剥完之后,逻辑是不是清晰多了?

现在请回到 Power Query 界面: 那么应该 1.1 对应的父级是 0,而 1.1.1 对应的父级是 1.1

© 版权声明
THE END
喜欢就支持一下吧
点赞785 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容