Skip to content
Advertisement

Oracle SQL/PLSQL: Hierarchical recursive query

I have asked very similar questions before but still haven’t achieved the correct result… third times the charm but I now have a stable parent-child relationship to work with.

Every row in the multi-level data set has a cost. For a specific row I need to find the lowest level and roll-up the cost. Then my users will compare the rolled up cost to the row cost and troubleshoot when/if they find differences.

SQL Fiddle here

Data Sample:

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

I am looking for a function or SQL statement, based on a specific row in the data set (MODEL_NO, MODEL_REV, P_SEQ_NO, SEQ_NO make a unique key) would return the cost roll-up.

For example: Based on this record: 1000, 1, 300, 1100, I would expect a result of: 232.

This is worked out by multiplying the UNIT_COST of each lowest level child by its QTY, adding the sum of each child together, then multiplying the result by the QTY of the parent, repeating the last step until you each the record entered, in this case SEQ_NO = 1100.

Result workings: (22*1 + 4*1 + 3*1 + 1*1 + 28*1) *4

This example is only 1 level deep, my data can go as deep as 6/7 levels.

Advertisement

Answer

I think you need to do this in two steps.

In step 1, you create the hierarchical query results and explode the quantities down to each level. For example, is you have a path like 100->210->320 and the qty values for those are 2, 3, and 5 respectively, then you have exploded quantities 2, 6, and 30, respectively.

Then, having that, you can multiply those exploded quantities by the unit code to get how much that row will contribute to the overall cost of all its parent levels. You can then summarize those costs with a scalar subquery.

Here is the query:

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 |
+-----+----------+--------+-----------+-----+--------------+---------------+-----+-------------------------+----------------+

NOTE #1

You did not indicate what the unit_cost represents for rows that are not leaf nodes in the hierarchy. Do they add to the cost of their children somehow? That will change the answer.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement