参考前一行而不是父行的分层查询

Hierarchical query with reference to previous row, not parent row

我有一个 table 详细列出了具有当前状态的对象列表以及完成之前需要执行的操作列表。

ProductId    CurrentWeight    RemainingRoute
001          50               M1-M7-M5
002          48               M3-M2-M9

我想把这个转换成操作列表table如下

ProductId    CurrentWeight    Machine
001/1        50               M1
001/2        50               M7
001/3        50               M5
002/1        48               M3
002/2        48               M2
002/3        48               M9

这个查询很容易:

SELECT ProductId || ‘/‘ || level, REGEXP_SUBSTR(RemainingRoute, ‘[^-]+’,1, LEVEL), CurrentWeight
FROM TABLE
CONNECT BY LEVEL <= REGEXP_COUNT(RemainingRoute, ‘-’) + 1
AND PRIOR ProductId = ProductId
AND PRIOR SYS_GUID() is not null;

问题来了。我需要计算产品在每次操作后掉落的最终重量 - 每台机器都有不同的产量系数。

这意味着我需要一个分层查询,我应该查看前一行(不是父行)的权重并乘以相应机器的产量。

我当前的查询是:

SELECT REGEXP_SUBSTR(RemainingRoute, ‘[^-]+’,1, LEVEL), CASE LEVEL WHEN 1 THEN CurrentWeight ELSE ( CASE REGEXP_SUBSTR(RemainingRoute, ‘[^-]+’,1, LEVEL) WHEN ‘M1’ THEN 0.95 * PRIOR WeightAfter WHEN ‘M7’  THEN 0.9 * PRIOR WeightAfter END ) END AS WeightAfter
FROM TABLE
CONNECT BY LEVEL <= REGEXP_COUNT(RemainingRoute, ‘-’) + 1
AND PRIOR ProductId = ProductId
AND PRIOR SYS_GUID() is not null;

这个查询确实有两个问题(它不起作用) 1. 我想访问一个字段的前一级值而不是父级值 -> PRIOR 不是正确的命令 2. 我递归地使用字段 WeightAfter,因为我在 WeightAfter 变量定义中引用它 - 我知道这是错误的,但不知道如何规避它。

非常感谢任何建议

您可能正在寻找如下所示的内容。请注意,没有分析(和聚合)product 函数,我不得不通过获取日志、分析 sum 和指数函数来模拟它。

我不明白为什么必须将 productid 和级别(我称之为 "step")组合在一个字符串中;当然,如果你愿意,你可以这样做,但我会按照我认为应该的方式显示输出。此外,在输出中不清楚您必须显示什么重量(或者更确切地说,为什么) - 产品到达机器之前或由该机器处理之后的重量?我在每一行都显示了两者(以及任何处理开始之前的原始重量);决定您的报告实际需要什么。

我模拟了您在 WITH 子句中的输入,但是您当然应该使用实际的 table(带有它们的 table 和列名)。我希望您有一个 table 就像我查询中的 MACHINES 视图一样。我使用了左外连接以防万一机器实际上没有显示在 MACHINES table 中,尽管这是不允许的。 (不确定如何 强制执行 鉴于您的数据模型直接违反第一范式。)如果机器不存在于 MACHINES table,它的屈服因子在查询中被视为 1.00。在此示例中,机器 'M9' 会发生这种情况。

with
  sample_inputs (productid, currentweight, remainingroute) as (
    select '001', 50, 'M1-M7-M5' from dual union all
    select '002', 48, 'M3-M2-M9' from dual
  )
, machines (machine, yield_factor) as (
    select 'M1', 0.95 from dual union all
    select 'M7', 0.90 from dual union all
    select 'M3', 0.80 from dual union all
    select 'M4', 1.00 from dual union all
    select 'M6', 0.92 from dual union all
    select 'M2', 0.90 from dual union all
    select 'M5', 0.86 from dual
  )
, routes (productid, step, currentweight, machine) as (
    select productid, level, currentweight,
           regexp_substr(remainingroute, '[^-]+', 1, level)
    from   sample_inputs
    connect by  level <= regexp_count(remainingroute, '[^-]+')
            and prior productid = productid
            and prior sys_guid() is not null
  )
, weights (productid, step, original_weight, machine, weight_out) as (
    select r.productid, r.step, r.currentweight, r.machine,
           round(r.currentweight *
                   exp(sum(ln(m.yield_factor)) 
                     over (partition by r.productid order by r.step)), 2)
    from   routes r left outer join machines m on r.machine = m.machine
  )
select productid, step, original_weight, machine,
       lag(weight_out, 1, original_weight)
         over (partition by productid order by step) as weight_in, weight_out
from   weights
order  by productid, step;

输出:

PRODUCTID  STEP ORIGINAL_WEIGHT MACHINE       WEIGHT_IN      WEIGHT_OUT
---------- ---- --------------- ------- --------------- ---------------
001           1           50.00 M1                50.00           47.50
001           2           50.00 M7                47.50           42.75
001           3           50.00 M5                42.75           36.76
002           1           48.00 M3                48.00           38.40
002           2           48.00 M2                38.40           34.56
002           3           48.00 M9                34.56           34.56