Oracle SQL / PL SQL: Иерархический рекурсивный запрос - PullRequest
0 голосов
/ 04 февраля 2020

Я задавал очень похожие вопросы раньше, но все еще не достиг правильного результата ... в три раза больше очарования, но теперь у меня стабильные отношения между родителями и детьми.

Каждая строка в Многоуровневый набор данных имеет свою стоимость. Для конкретной строки c мне нужно найти самый низкий уровень и свернуть стоимость. Затем мои пользователи будут сравнивать свернутую стоимость со стоимостью строки и устранять неполадки, когда / если они обнаружат различия.

SQL Fiddle here

Образец данных:

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, основанный на определенной строке c в наборе данных (MODEL_NO, MODEL_REV, P_SEQ_NO, SEQ_NO делают уникальным key) вернет сворачивание стоимости.

Например: На основании этой записи: 1000, 1, 300, 1100, я ожидаю результат: 232.

Это разработано умножение UNIT_COST каждого дочернего элемента самого низкого уровня на его QTY, сложение суммы каждого дочернего элемента вместе, затем умножение результата на QTY родительского элемента, повторение последнего шага, пока вы не введете каждую запись, в этом case SEQ_NO = 1100.

Результат работы: (22*1 + 4*1 + 3*1 + 1*1 + 28*1) *4

Этот пример имеет глубину только 1 уровень, мои данные могут go глубиной до 6/7 уровней.

1 Ответ

2 голосов
/ 04 февраля 2020

Я думаю, вам нужно сделать это в два шага.

На шаге 1 вы создаете результаты иерархического запроса и разбиваете количества вниз до каждого уровня. Например, если у вас есть путь, например 100-> 210-> 320, и значения qty для них равны 2, 3 и 5 соответственно, то вы взорвали величины 2, 6 и 30 соответственно.

Затем, имея это, вы можете умножить эти разнесенные количества на код единицы, чтобы получить, сколько эта строка будет вносить в общую стоимость всех своих родительских уровней. Затем вы можете суммировать эти затраты с помощью скалярного подзапроса.

Вот запрос:

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 не указывает, что unit_cost представляет для строк, которые не являются конечными узлами в иерархии. Они как-то увеличивают стоимость своих детей? Это изменит ответ.

...