Oracle SQL «соединяйся по-прежнему» - сумма и произведение значений сохраняются в дереве - PullRequest
0 голосов
/ 03 ноября 2018

Следующий SQL:

WITH vehicle_build_structure (part_no, parent_part, qty_per_assembly) AS (
   SELECT 'LORRY',    '*',     null FROM dual UNION -- if it makes things easier, you may substitute "null" for "1"
   SELECT 'AXLEA',    'LORRY', 3    FROM dual UNION
   SELECT 'BRAKEPAD', 'AXLEA', 2    FROM dual UNION
   SELECT 'WHEEL',    'AXLEA', 4    FROM dual UNION
   SELECT 'CAR',      '*',     null FROM dual UNION
   SELECT 'AXLEB',    'CAR',   2    FROM dual UNION
   SELECT 'BRAKEPAD', 'AXLEB', 2    FROM dual UNION
   SELECT 'WHEEL',    'AXLEB', 2    FROM dual
), exploded_structure AS (
   SELECT level lev, CONNECT_BY_ROOT s.part_no top_level_part, s.part_no, s.qty_per_assembly,
          (
             SELECT sum (sp.qty_per_assembly)
             FROM   vehicle_build_structure sp
             START WITH sp.part_no = s.part_no
             CONNECT BY prior sp.parent_part = sp.part_no
          ) sum_of_structure,
          (
             SELECT exp(sum(ln(sp.qty_per_assembly)))
             FROM   vehicle_build_structure sp
             START WITH sp.part_no = s.part_no
             CONNECT BY prior sp.parent_part = sp.part_no
          ) product_of_structure
   FROM   vehicle_build_structure s
   START WITH s.parent_part = '*'
   CONNECT BY prior s.part_no = s.parent_part
)
SELECT e.lev, e.top_level_part, e.part_no, e.qty_per_assembly,
       e.sum_of_structure, e.product_of_structure
FROM   exploded_structure e

Создает следующую сетку:

       LEV TOP_LEVE PART_NO  QTY_PER_ASSEMBLY SUM_OF_STRUCTURE PRODUCT_OF_STRUCTURE
---------- -------- -------- ---------------- ---------------- --------------------
         1 CAR      CAR
         2 CAR      AXLEB                   2                2                    2
         3 CAR      BRAKEPAD                2                9                   24
         3 CAR      WHEEL                   2               11                   48
         1 LORRY    LORRY
         2 LORRY    AXLEA                   3                3                    3
         3 LORRY    BRAKEPAD                2                9                   24
         3 LORRY    WHEEL                   4               11                   48

Но мне нужно, чтобы создать эту сетку:

       LEV TOP_LEVE PART_NO  QTY_PER_ASSEMBLY SUM_OF_STRUCTURE PRODUCT_OF_STRUCTURE
---------- -------- -------- ---------------- ---------------- --------------------
         1 CAR      CAR
         2 CAR      AXLEB                   2                2                    2
         3 CAR      BRAKEPAD                2                4                    4
         3 CAR      WHEEL                   2                4                    4
         1 LORRY    LORRY
         2 LORRY    AXLEA                   3                3                    3
         3 LORRY    BRAKEPAD                2                5                    6
         3 LORRY    WHEEL                   4                7                   12

Другими словами, мне нужен SQL, чтобы сказать мне, что когда я собираю автомобиль, мне нужно 4 колеса, а когда я собираю грузовик, мне нужно 12 колес.

Однако, поскольку часть WHEEL является частью как структур CAR, так и LORRY, внутренний оператор connect-by-prior выполняет резервное копирование обеих ветвей и умножает количества обеих структур вместе (12 * 4 = 48). Очевидно, что когда структура становится очень сложной, это приводит к крайне неправильному ответу.

Я не могу понять, как ограничить этот внутренний оператор connect-by-before только для того, чтобы вернуться обратно в ветку от того места, куда он пришел.

Может кто-нибудь помочь?

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

Я чувствую, что это немного прыгает через обручи, но это работает. По сути, вы записываете свои вычисления, проходя по дереву, а затем выполняете eval() на вычислении, которое вы определили.

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

WITH vehicle_build_structure (part_no, parent_part, qty_per_assembly) AS (
   SELECT 'LORRY',    '*',     null FROM dual UNION
   SELECT 'AXLEA',    'LORRY', 3    FROM dual UNION
   SELECT 'BRAKEPAD', 'AXLEA', 2    FROM dual UNION
   SELECT 'WHEEL',    'AXLEA', 4    FROM dual UNION
   SELECT 'CAR',      '*',     null FROM dual UNION
   SELECT 'AXLEB',    'CAR',   2    FROM dual UNION
   SELECT 'BRAKEPAD', 'AXLEB', 2    FROM dual UNION
   SELECT 'WHEEL',    'AXLEB', 2    FROM dual
), exploded_structure AS (
   SELECT level lev, CONNECT_BY_ROOT s.part_no top_level_part, s.part_no, s.qty_per_assembly,
          nvl (ltrim (sys_connect_by_path (s.qty_per_assembly, '*'), '*'), 0) my_calculation
   FROM   vehicle_build_structure s
   START WITH s.parent_part = '*'
   CONNECT BY prior s.part_no = s.parent_part
)
SELECT e.lev, e.top_level_part, e.part_no, e.qty_per_assembly, e.my_calculation,
       xmlquery (e.my_calculation returning content).getnumberval() my_result
FROM   exploded_structure e

Производит:

       LEV TOP_LEVE PART_NO  QTY_PER_ASSEMBLY MY_CALCULATION                  MY_RESULT
---------- -------- -------- ---------------- ------------------------------ ----------
         1 CAR      CAR                       0                                       0
         2 CAR      AXLEB                   2 2                                       2
         3 CAR      BRAKEPAD                2 2*2                                     4
         3 CAR      WHEEL                   2 2*2                                     4
         1 LORRY    LORRY                     0                                       0
         2 LORRY    AXLEA                   3 3                                       3
         3 LORRY    BRAKEPAD                2 3*2                                     6
         3 LORRY    WHEEL                   4 3*4                                    12
0 голосов
/ 03 ноября 2018

Я думаю, вам следует попробовать что-то сделать с дублирующимися значениями в столбце part_no. Расширить дерево за пределы «тормозной колодки» и «колеса» будет сложно с вашим столом.

При этом запрос, который вы ищете, должен выглядеть так (не тестировался на Oracle, пожалуйста, исправьте любую опечатку):

WITH vehicle_build_structure (part_no, parent_part, qty_per_assembly) AS (
   SELECT 'LORRY',    '*',     null FROM dual UNION
   SELECT 'AXLEA',    'LORRY', 3    FROM dual UNION
   SELECT 'BRAKEPAD', 'AXLEA', 2    FROM dual UNION
   SELECT 'WHEEL',    'AXLEA', 4    FROM dual UNION
   SELECT 'CAR',      '*',     null FROM dual UNION
   SELECT 'AXLEB',    'CAR',   2    FROM dual UNION
   SELECT 'BRAKEPAD', 'AXLEB', 2    FROM dual UNION
   SELECT 'WHEEL',    'AXLEB', 2    FROM dual
), rec_build_structure (lv, top_part, part_no, qty_per_assembly, qty_sum, qty_product) AS (
    SELECT 1, part_no, part_no, 1, 0, 1
    FROM   vehicle_build_structure
    WHERE  parent_part = '*'
    UNION ALL
    SELECT 1 + r.lv, r.top_part, v.part_no, v.qty_per_assembly,
           v.qty_per_assembly + r.qty_sum,
           v.qty_per_assembly * r.qty_product
    FROM   vehicle_build_structure v
           INNER JOIN rec_build_structure r
                   ON v.parent_part = r.part_no
)
SELECT rbs.*
FROM   rec_build_structure rbs
ORDER BY rbs.top_part, rbs.lv, rbs.part_no
...