Oracle SQL/PLSQL: 分层递归查询
Oracle SQL/PLSQL: Hierarchical recursive query
我以前问过非常相似的问题,但仍然没有得到正确的结果...第三次魅力,但我现在有稳定的 parent-child 工作关系。
multi-level 数据集中的每一行都有一个成本。对于特定行,我需要找到最低级别和 roll-up 成本。然后,我的用户会将汇总成本与行成本进行比较,然后进行故障排除 when/if 他们会发现差异。
数据样本:
MODEL_NO MODEL_REV P_SEQ_NO SEQ_NO UNIT_COST QTY LEVEL TREE_PATH ISLEAF
1000 1 100 300 8889 1 1 >300 0
1000 1 300 400 1701 1 2 >300>400 1
1000 1 300 500 970 1 2 >300>500 1
1000 1 300 600 7 2 2 >300>600 1
1000 1 300 700 1160 1 2 >300>700 1
1000 1 300 800 580 1 2 >300>800 1
1000 1 300 900 96 1 2 >300>900 1
1000 1 300 1000 350 1 2 >300>1000 1
1000 1 300 1100 59 4 2 >300>1100 0
1000 1 1100 1200 28 1 3 >300>1100>1200 1
1000 1 1100 1300 1 1 3 >300>1100>1300 1
1000 1 1100 1400 3 1 3 >300>1100>1400 1
1000 1 1100 1500 4 1 3 >300>1100>1500 1
1000 1 1100 1600 22 1 3 >300>1100>1600 1
我正在寻找函数或 SQL 语句,基于数据集中的特定行(MODEL_NO
、MODEL_REV
、P_SEQ_NO
、SEQ_NO
制作一个唯一的密钥)将 return 成本 roll-up.
例如:
基于此记录:1000, 1, 300, 1100
,
我期望的结果是:232
.
这是通过将每个最低级别 child 的 UNIT_COST
乘以其 QTY
,将每个 child 的总和相加,然后乘以结果得出的通过 parent 的 QTY
,重复最后一步,直到您输入每条记录,在本例中为 SEQ_NO = 1100
.
结果工作:(22*1 + 4*1 + 3*1 + 1*1 + 28*1) *4
这个例子只有 1 级深,我的数据可以达到 6/7 级。
我认为你需要分两步完成。
在第 1 步中,您创建分层查询结果并将数量分解到每个级别。例如,如果您有一条类似 100->210->320 的路径,并且这些路径的 qty
值分别为 2、3 和 5,那么您的分解数量分别为 2、6 和 30。
然后,有了它,您可以将这些展开的数量乘以单位代码,得到该行将占其所有 parent 级别的总成本的多少。然后,您可以使用标量子查询汇总这些成本。
这里是查询:
WITH c ( model_no, model_rev, lvl, p_seq_no, seq_no, unit_cost, qty, exploded_qty, pth) AS
( SELECT model_no, model_rev, 1 lvl, p_seq_no, seq_no, unit_cost, qty, qty exploded_qty, to_char(seq_no) pth
FROM prod_cost_model_struct_tab
WHERE model_no = 1000
AND model_rev = 1
AND seq_no = 300
UNION ALL
SELECT child.model_no, child.model_rev, parent.lvl+1, child.p_seq_no, child.seq_no, child.unit_cost, child.qty, parent.exploded_qty * child.qty exploded_qty, parent.pth || '>' || child.seq_no pth
FROM prod_cost_model_struct_tab child INNER JOIN c parent
ON child.model_no = parent.model_no
AND child.model_rev = parent.model_rev
AND child.p_seq_no = parent.seq_no )
search depth first by seq_no set ord,
exploded_qtys AS (
SELECT lvl,
c.p_seq_no,
c.seq_no,
c.unit_cost,
c.qty,
c.exploded_qty,
c.pth,
c.ord,
case when (lvl - lead(lvl) over (order by ord)) < 0 then
-- It is not a leaf, level contributes nothing (assumption: see question)
-- QUESTION: What does the unit_cost represent on non-leaf rows?
0 ELSE c.exploded_qty * c.unit_cost END level_cost_contribution
FROM c )
SELECT e.*, ( SELECT nvl(sum(level_cost_contribution),0) FROM exploded_qtys e2 WHERE e2.pth LIKE e.pth || '>%' ) + level_cost_contribution aggregate_cost
FROM exploded_qtys e
+-----+----------+--------+-----------+-----+--------------+---------------+-----+-------------------------+----------------+
| LVL | P_SEQ_NO | SEQ_NO | UNIT_COST | QTY | EXPLODED_QTY | PTH | ORD | LEVEL_COST_CONTRIBUTION | AGGREGATE_COST |
+-----+----------+--------+-----------+-----+--------------+---------------+-----+-------------------------+----------------+
| 1 | 100 | 300 | 8889 | 1 | 1 | 300 | 1 | 0 | 8783 |
| 2 | 300 | 400 | 1701 | 1 | 1 | 300>400 | 2 | 1701 | 1701 |
| 2 | 300 | 500 | 970 | 1 | 1 | 300>500 | 3 | 970 | 970 |
| 2 | 300 | 600 | 7 | 2 | 2 | 300>600 | 4 | 14 | 14 |
| 2 | 300 | 700 | 1160 | 1 | 1 | 300>700 | 5 | 1160 | 1160 |
| 2 | 300 | 800 | 580 | 1 | 1 | 300>800 | 6 | 580 | 580 |
| 2 | 300 | 900 | 96 | 1 | 1 | 300>900 | 7 | 96 | 96 |
| 2 | 300 | 1000 | 350 | 1 | 1 | 300>1000 | 8 | 350 | 350 |
| 2 | 300 | 1100 | 59 | 4 | 4 | 300>1100 | 9 | 0 | 232 |
| 3 | 1100 | 1200 | 28 | 1 | 4 | 300>1100>1200 | 10 | 112 | 112 |
| 3 | 1100 | 1300 | 1 | 1 | 4 | 300>1100>1300 | 11 | 4 | 4 |
| 3 | 1100 | 1400 | 3 | 1 | 4 | 300>1100>1400 | 12 | 12 | 12 |
| 3 | 1100 | 1500 | 4 | 1 | 4 | 300>1100>1500 | 13 | 16 | 16 |
| 3 | 1100 | 1600 | 22 | 1 | 4 | 300>1100>1600 | 14 | 88 | 88 |
| 2 | 300 | 1700 | 219 | 1 | 1 | 300>1700 | 15 | 0 | 218 |
| 3 | 1700 | 1800 | 10 | 1 | 1 | 300>1700>1800 | 16 | 10 | 10 |
| 3 | 1700 | 1900 | 1 | 4 | 4 | 300>1700>1900 | 17 | 4 | 4 |
| 3 | 1700 | 2000 | 200 | 1 | 1 | 300>1700>2000 | 18 | 200 | 200 |
| 3 | 1700 | 2100 | 4 | 1 | 1 | 300>1700>2100 | 19 | 4 | 4 |
| 2 | 300 | 2200 | 1160 | 1 | 1 | 300>2200 | 20 | 1160 | 1160 |
| 2 | 300 | 2300 | 1 | 8 | 8 | 300>2300 | 21 | 8 | 8 |
| 2 | 300 | 2400 | 1 | 2 | 2 | 300>2400 | 22 | 2 | 2 |
| 2 | 300 | 2500 | 1 | 1 | 1 | 300>2500 | 23 | 1 | 1 |
| 2 | 300 | 2600 | 2 | 1 | 1 | 300>2600 | 24 | 2 | 2 |
| 2 | 300 | 2700 | 4 | 2 | 2 | 300>2700 | 25 | 8 | 8 |
| 2 | 300 | 2800 | 103 | 1 | 1 | 300>2800 | 26 | 103 | 103 |
| 2 | 300 | 2900 | 95 | 1 | 1 | 300>2900 | 27 | 95 | 95 |
| 2 | 300 | 3000 | 0 | 4 | 4 | 300>3000 | 28 | 0 | 0 |
| 2 | 300 | 3100 | 2 | 1 | 1 | 300>3100 | 29 | 2 | 2 |
| 2 | 300 | 3200 | 0 | 66 | 66 | 300>3200 | 30 | 0 | 0 |
| 2 | 300 | 3300 | 0 | 12 | 12 | 300>3300 | 31 | 0 | 0 |
| 2 | 300 | 3400 | 0 | 33 | 33 | 300>3400 | 32 | 0 | 0 |
| 2 | 300 | 3500 | 0 | 4 | 4 | 300>3500 | 33 | 0 | 0 |
| 2 | 300 | 3600 | 0 | 8 | 8 | 300>3600 | 34 | 0 | 0 |
| 2 | 300 | 3700 | 0 | 4 | 4 | 300>3700 | 35 | 0 | 0 |
| 2 | 300 | 3800 | 0 | 4 | 4 | 300>3800 | 36 | 0 | 0 |
| 2 | 300 | 3900 | 0 | 5 | 5 | 300>3900 | 37 | 0 | 0 |
| 2 | 300 | 4000 | 0 | 84 | 84 | 300>4000 | 38 | 0 | 0 |
| 2 | 300 | 4100 | 0 | 32 | 32 | 300>4100 | 39 | 0 | 0 |
| 2 | 300 | 4200 | 0 | 32 | 32 | 300>4200 | 40 | 0 | 0 |
| 2 | 300 | 4300 | 1 | 12 | 12 | 300>4300 | 41 | 12 | 12 |
| 2 | 300 | 4400 | 2 | 3 | 3 | 300>4400 | 42 | 6 | 6 |
| 2 | 300 | 4500 | 145 | 1 | 1 | 300>4500 | 43 | 145 | 145 |
| 2 | 300 | 4600 | 48 | 1 | 1 | 300>4600 | 44 | 48 | 48 |
| 2 | 300 | 4700 | 2 | 2 | 2 | 300>4700 | 45 | 4 | 4 |
| 2 | 300 | 4800 | 1846 | 1 | 1 | 300>4800 | 46 | 0 | 1832 |
| 3 | 4800 | 4900 | 169 | 3 | 3 | 300>4800>4900 | 47 | 507 | 507 |
| 3 | 4800 | 5000 | 30 | 1 | 1 | 300>4800>5000 | 48 | 30 | 30 |
| 3 | 4800 | 5100 | 17 | 1 | 1 | 300>4800>5100 | 49 | 17 | 17 |
| 3 | 4800 | 5200 | 169 | 3 | 3 | 300>4800>5200 | 50 | 507 | 507 |
| 3 | 4800 | 5300 | 5 | 1 | 1 | 300>4800>5300 | 51 | 5 | 5 |
| 3 | 4800 | 5400 | 320 | 1 | 1 | 300>4800>5400 | 52 | 320 | 320 |
| 3 | 4800 | 5500 | 25 | 2 | 2 | 300>4800>5500 | 53 | 50 | 50 |
| 3 | 4800 | 5600 | 5 | 4 | 4 | 300>4800>5600 | 54 | 20 | 20 |
| 3 | 4800 | 5700 | 18 | 3 | 3 | 300>4800>5700 | 55 | 54 | 54 |
| 3 | 4800 | 5800 | 139 | 2 | 2 | 300>4800>5800 | 56 | 278 | 278 |
| 3 | 4800 | 5900 | 8 | 2 | 2 | 300>4800>5900 | 57 | 16 | 16 |
| 3 | 4800 | 6000 | 9 | 1 | 1 | 300>4800>6000 | 58 | 9 | 9 |
| 3 | 4800 | 6100 | 19 | 1 | 1 | 300>4800>6100 | 59 | 19 | 19 |
| 2 | 300 | 6200 | 25 | 1 | 1 | 300>6200 | 60 | 25 | 25 |
| 2 | 300 | 6300 | 9 | 1 | 1 | 300>6300 | 61 | 9 | 9 |
+-----+----------+--------+-----------+-----+--------------+---------------+-----+-------------------------+----------------+
注意#1
您没有指出 unit_cost
代表层次结构中非叶节点的行。他们会以某种方式增加 children 的成本吗?这将改变答案。
我以前问过非常相似的问题,但仍然没有得到正确的结果...第三次魅力,但我现在有稳定的 parent-child 工作关系。
multi-level 数据集中的每一行都有一个成本。对于特定行,我需要找到最低级别和 roll-up 成本。然后,我的用户会将汇总成本与行成本进行比较,然后进行故障排除 when/if 他们会发现差异。
数据样本:
MODEL_NO MODEL_REV P_SEQ_NO SEQ_NO UNIT_COST QTY LEVEL TREE_PATH ISLEAF
1000 1 100 300 8889 1 1 >300 0
1000 1 300 400 1701 1 2 >300>400 1
1000 1 300 500 970 1 2 >300>500 1
1000 1 300 600 7 2 2 >300>600 1
1000 1 300 700 1160 1 2 >300>700 1
1000 1 300 800 580 1 2 >300>800 1
1000 1 300 900 96 1 2 >300>900 1
1000 1 300 1000 350 1 2 >300>1000 1
1000 1 300 1100 59 4 2 >300>1100 0
1000 1 1100 1200 28 1 3 >300>1100>1200 1
1000 1 1100 1300 1 1 3 >300>1100>1300 1
1000 1 1100 1400 3 1 3 >300>1100>1400 1
1000 1 1100 1500 4 1 3 >300>1100>1500 1
1000 1 1100 1600 22 1 3 >300>1100>1600 1
我正在寻找函数或 SQL 语句,基于数据集中的特定行(MODEL_NO
、MODEL_REV
、P_SEQ_NO
、SEQ_NO
制作一个唯一的密钥)将 return 成本 roll-up.
例如:
基于此记录:1000, 1, 300, 1100
,
我期望的结果是:232
.
这是通过将每个最低级别 child 的 UNIT_COST
乘以其 QTY
,将每个 child 的总和相加,然后乘以结果得出的通过 parent 的 QTY
,重复最后一步,直到您输入每条记录,在本例中为 SEQ_NO = 1100
.
结果工作:(22*1 + 4*1 + 3*1 + 1*1 + 28*1) *4
这个例子只有 1 级深,我的数据可以达到 6/7 级。
我认为你需要分两步完成。
在第 1 步中,您创建分层查询结果并将数量分解到每个级别。例如,如果您有一条类似 100->210->320 的路径,并且这些路径的 qty
值分别为 2、3 和 5,那么您的分解数量分别为 2、6 和 30。
然后,有了它,您可以将这些展开的数量乘以单位代码,得到该行将占其所有 parent 级别的总成本的多少。然后,您可以使用标量子查询汇总这些成本。
这里是查询:
WITH c ( model_no, model_rev, lvl, p_seq_no, seq_no, unit_cost, qty, exploded_qty, pth) AS
( SELECT model_no, model_rev, 1 lvl, p_seq_no, seq_no, unit_cost, qty, qty exploded_qty, to_char(seq_no) pth
FROM prod_cost_model_struct_tab
WHERE model_no = 1000
AND model_rev = 1
AND seq_no = 300
UNION ALL
SELECT child.model_no, child.model_rev, parent.lvl+1, child.p_seq_no, child.seq_no, child.unit_cost, child.qty, parent.exploded_qty * child.qty exploded_qty, parent.pth || '>' || child.seq_no pth
FROM prod_cost_model_struct_tab child INNER JOIN c parent
ON child.model_no = parent.model_no
AND child.model_rev = parent.model_rev
AND child.p_seq_no = parent.seq_no )
search depth first by seq_no set ord,
exploded_qtys AS (
SELECT lvl,
c.p_seq_no,
c.seq_no,
c.unit_cost,
c.qty,
c.exploded_qty,
c.pth,
c.ord,
case when (lvl - lead(lvl) over (order by ord)) < 0 then
-- It is not a leaf, level contributes nothing (assumption: see question)
-- QUESTION: What does the unit_cost represent on non-leaf rows?
0 ELSE c.exploded_qty * c.unit_cost END level_cost_contribution
FROM c )
SELECT e.*, ( SELECT nvl(sum(level_cost_contribution),0) FROM exploded_qtys e2 WHERE e2.pth LIKE e.pth || '>%' ) + level_cost_contribution aggregate_cost
FROM exploded_qtys e
+-----+----------+--------+-----------+-----+--------------+---------------+-----+-------------------------+----------------+ | LVL | P_SEQ_NO | SEQ_NO | UNIT_COST | QTY | EXPLODED_QTY | PTH | ORD | LEVEL_COST_CONTRIBUTION | AGGREGATE_COST | +-----+----------+--------+-----------+-----+--------------+---------------+-----+-------------------------+----------------+ | 1 | 100 | 300 | 8889 | 1 | 1 | 300 | 1 | 0 | 8783 | | 2 | 300 | 400 | 1701 | 1 | 1 | 300>400 | 2 | 1701 | 1701 | | 2 | 300 | 500 | 970 | 1 | 1 | 300>500 | 3 | 970 | 970 | | 2 | 300 | 600 | 7 | 2 | 2 | 300>600 | 4 | 14 | 14 | | 2 | 300 | 700 | 1160 | 1 | 1 | 300>700 | 5 | 1160 | 1160 | | 2 | 300 | 800 | 580 | 1 | 1 | 300>800 | 6 | 580 | 580 | | 2 | 300 | 900 | 96 | 1 | 1 | 300>900 | 7 | 96 | 96 | | 2 | 300 | 1000 | 350 | 1 | 1 | 300>1000 | 8 | 350 | 350 | | 2 | 300 | 1100 | 59 | 4 | 4 | 300>1100 | 9 | 0 | 232 | | 3 | 1100 | 1200 | 28 | 1 | 4 | 300>1100>1200 | 10 | 112 | 112 | | 3 | 1100 | 1300 | 1 | 1 | 4 | 300>1100>1300 | 11 | 4 | 4 | | 3 | 1100 | 1400 | 3 | 1 | 4 | 300>1100>1400 | 12 | 12 | 12 | | 3 | 1100 | 1500 | 4 | 1 | 4 | 300>1100>1500 | 13 | 16 | 16 | | 3 | 1100 | 1600 | 22 | 1 | 4 | 300>1100>1600 | 14 | 88 | 88 | | 2 | 300 | 1700 | 219 | 1 | 1 | 300>1700 | 15 | 0 | 218 | | 3 | 1700 | 1800 | 10 | 1 | 1 | 300>1700>1800 | 16 | 10 | 10 | | 3 | 1700 | 1900 | 1 | 4 | 4 | 300>1700>1900 | 17 | 4 | 4 | | 3 | 1700 | 2000 | 200 | 1 | 1 | 300>1700>2000 | 18 | 200 | 200 | | 3 | 1700 | 2100 | 4 | 1 | 1 | 300>1700>2100 | 19 | 4 | 4 | | 2 | 300 | 2200 | 1160 | 1 | 1 | 300>2200 | 20 | 1160 | 1160 | | 2 | 300 | 2300 | 1 | 8 | 8 | 300>2300 | 21 | 8 | 8 | | 2 | 300 | 2400 | 1 | 2 | 2 | 300>2400 | 22 | 2 | 2 | | 2 | 300 | 2500 | 1 | 1 | 1 | 300>2500 | 23 | 1 | 1 | | 2 | 300 | 2600 | 2 | 1 | 1 | 300>2600 | 24 | 2 | 2 | | 2 | 300 | 2700 | 4 | 2 | 2 | 300>2700 | 25 | 8 | 8 | | 2 | 300 | 2800 | 103 | 1 | 1 | 300>2800 | 26 | 103 | 103 | | 2 | 300 | 2900 | 95 | 1 | 1 | 300>2900 | 27 | 95 | 95 | | 2 | 300 | 3000 | 0 | 4 | 4 | 300>3000 | 28 | 0 | 0 | | 2 | 300 | 3100 | 2 | 1 | 1 | 300>3100 | 29 | 2 | 2 | | 2 | 300 | 3200 | 0 | 66 | 66 | 300>3200 | 30 | 0 | 0 | | 2 | 300 | 3300 | 0 | 12 | 12 | 300>3300 | 31 | 0 | 0 | | 2 | 300 | 3400 | 0 | 33 | 33 | 300>3400 | 32 | 0 | 0 | | 2 | 300 | 3500 | 0 | 4 | 4 | 300>3500 | 33 | 0 | 0 | | 2 | 300 | 3600 | 0 | 8 | 8 | 300>3600 | 34 | 0 | 0 | | 2 | 300 | 3700 | 0 | 4 | 4 | 300>3700 | 35 | 0 | 0 | | 2 | 300 | 3800 | 0 | 4 | 4 | 300>3800 | 36 | 0 | 0 | | 2 | 300 | 3900 | 0 | 5 | 5 | 300>3900 | 37 | 0 | 0 | | 2 | 300 | 4000 | 0 | 84 | 84 | 300>4000 | 38 | 0 | 0 | | 2 | 300 | 4100 | 0 | 32 | 32 | 300>4100 | 39 | 0 | 0 | | 2 | 300 | 4200 | 0 | 32 | 32 | 300>4200 | 40 | 0 | 0 | | 2 | 300 | 4300 | 1 | 12 | 12 | 300>4300 | 41 | 12 | 12 | | 2 | 300 | 4400 | 2 | 3 | 3 | 300>4400 | 42 | 6 | 6 | | 2 | 300 | 4500 | 145 | 1 | 1 | 300>4500 | 43 | 145 | 145 | | 2 | 300 | 4600 | 48 | 1 | 1 | 300>4600 | 44 | 48 | 48 | | 2 | 300 | 4700 | 2 | 2 | 2 | 300>4700 | 45 | 4 | 4 | | 2 | 300 | 4800 | 1846 | 1 | 1 | 300>4800 | 46 | 0 | 1832 | | 3 | 4800 | 4900 | 169 | 3 | 3 | 300>4800>4900 | 47 | 507 | 507 | | 3 | 4800 | 5000 | 30 | 1 | 1 | 300>4800>5000 | 48 | 30 | 30 | | 3 | 4800 | 5100 | 17 | 1 | 1 | 300>4800>5100 | 49 | 17 | 17 | | 3 | 4800 | 5200 | 169 | 3 | 3 | 300>4800>5200 | 50 | 507 | 507 | | 3 | 4800 | 5300 | 5 | 1 | 1 | 300>4800>5300 | 51 | 5 | 5 | | 3 | 4800 | 5400 | 320 | 1 | 1 | 300>4800>5400 | 52 | 320 | 320 | | 3 | 4800 | 5500 | 25 | 2 | 2 | 300>4800>5500 | 53 | 50 | 50 | | 3 | 4800 | 5600 | 5 | 4 | 4 | 300>4800>5600 | 54 | 20 | 20 | | 3 | 4800 | 5700 | 18 | 3 | 3 | 300>4800>5700 | 55 | 54 | 54 | | 3 | 4800 | 5800 | 139 | 2 | 2 | 300>4800>5800 | 56 | 278 | 278 | | 3 | 4800 | 5900 | 8 | 2 | 2 | 300>4800>5900 | 57 | 16 | 16 | | 3 | 4800 | 6000 | 9 | 1 | 1 | 300>4800>6000 | 58 | 9 | 9 | | 3 | 4800 | 6100 | 19 | 1 | 1 | 300>4800>6100 | 59 | 19 | 19 | | 2 | 300 | 6200 | 25 | 1 | 1 | 300>6200 | 60 | 25 | 25 | | 2 | 300 | 6300 | 9 | 1 | 1 | 300>6300 | 61 | 9 | 9 | +-----+----------+--------+-----------+-----+--------------+---------------+-----+-------------------------+----------------+
注意#1
您没有指出 unit_cost
代表层次结构中非叶节点的行。他们会以某种方式增加 children 的成本吗?这将改变答案。