Иерархический запрос со ссылкой на предыдущую строку, а не на родительскую строку - PullRequest
1 голос
/ 23 марта 2020

У меня есть таблица с подробным списком объектов с текущим состоянием и списком операций, которые необходимо выполнить перед завершением.

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

Я хотел бы преобразовать это в таблицу списка операций следующим образом

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 - я знаю, что это неправильно, но не знаю, как его обойти.

Любой совет высоко ценится

1 Ответ

2 голосов
/ 23 марта 2020

Вы, вероятно, ищете что-то, что я покажу ниже. Обратите внимание, что аналитической c (и агрегатной) product функции нет, мне пришлось ее смоделировать, взяв логи, аналитику c sum и экспоненциальную функцию.

Я не понимаю, почему вы должны объединить productid и уровень (я назвал это "step") в одну строку; конечно, вы можете сделать это, если вы sh, но я показываю результаты так, как я считаю. Кроме того, в выводе не ясно, какой вес вы должны показать (или, скорее, ПОЧЕМУ) - вес до того, как продукт поступит в машину, или после того, как он будет обработан этой машиной? Я показываю оба (а также исходный вес до начала обработки) в каждом ряду; решите, что вам действительно нужно для вашего отчета.

Я смоделировал ваши входные данные в предложении WITH, но, конечно, вы должны использовать ваши фактические таблицы (с их именами таблиц и столбцов). Я надеюсь, что у вас есть таблица, как представление MACHINES в моем запросе. Я использовал левое внешнее соединение на тот случай, если машина фактически не отображается в таблице MACHINES, хотя это не должно быть разрешено. (Не уверен, как вы можете применить , что, хотя, учитывая вашу модель данных, которая является прямым нарушением первой нормальной формы.) Если машина не присутствует в таблице MACHINES, ее коэффициент доходности рассматривается как 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
...