Боюсь, что вы все запутали :)
Хотя ваши требования частично трудно понять, я думаю, что есть одна вещь, которую я бы сделал, если бы мне пришлось решать такую задачу.Я написал бы рекурсивную функцию, вычисляющую стоимость от любой части дерева до листьев.
Вот демонстрация данных, аналогичных вашим:
select prod.*, level, sys_connect_by_path(seq, '->') path,
calc_cost(comp) total
from prod connect by prior comp = part
start with base = 1;
SEQ PART COMP QTY COST CURR BASE AFO RFO LEVEL PATH TOTAL
------ ---- ---- ---------- ---------- ---- ---------- --- --- ------- ----------- ----------
1 A A1 5 1 1 ->1 850
2 A1 A11 3 0 B 2 ->1->2 114
3 A11 A111 4 2 EUR 0 B;D 3 ->1->2->3 8
4 A11 A112 2 15 EUR 0 3 ->1->2->4 30
5 A1 A12 8 7 EUR 0 2 ->1->5 56
11 B B1 5 1 1 ->11 870
12 B1 B11 3 0 2 ->11->12 174
13 B11 B111 4 12 GBP 0 3 ->11->12->13 48
14 B11 B112 2 5 GBP 0 3 ->11->12->14 10
Столбец total
содержит затраты на компоненты, например, для B1
это 5 * (3 * (4 * 12 + 2 * 5))
, что составляет 870
.
Данные о функциях и примерах приведены здесь:
create or replace function calc_cost(i_comp in varchar2) return number is
v_qty number := 0;
v_cost number := 0;
begin
select qty, cost into v_qty, v_cost from prod where comp = i_comp;
if v_cost is null then
select sum(calc_cost(comp)) into v_cost from prod where part = i_comp;
end if;
return v_qty * v_cost;
exception when no_data_found then
return 0;
end;
Данные:
create table prod(seq, part, comp, qty, cost, curr, base, afo, rfo) as (
select 1, 'A', 'A1', 5, null, null, 1, null, null from dual union all
select 2, 'A1', 'A11', 3, null, null, 0, 'B', null from dual union all
select 3, 'A11', 'A111', 4, 2, 'EUR', 0, null, 'B;D' from dual union all
select 4, 'A11', 'A112', 2, 15, 'EUR', 0, null, null from dual union all
select 5, 'A1', 'A12', 8, 7, 'EUR', 0, null, null from dual union all
select 11, 'B', 'B1', 5, null, null, 1, null, null from dual union all
select 12, 'B1', 'B11', 3, null, null, 0, null, null from dual union all
select 13, 'B11', 'B111', 4, 12, 'GBP', 0, null, null from dual union all
select 14, 'B11', 'B112', 2, 5, 'GBP', 0, null, null from dual );
Вы не указали, могут ли разные валюты быть одинаковыми part
/ component
и, если да, то как будет выводиться, как.В любом случае вы можете найти эти валюты и сделать расчеты для каждой валюты независимо.Вам нужно добавить второй параметр в функцию и написать что-то вроде where part = i_comp and curr = i_curr or curr is null
.
Также для ask_for_option
/ remove_for_option
вы, вероятно, можете справиться с ними в case when
.
Я вижу, что вы приложили много усилий для решения этой проблемы, но в текущей форме вашего вопроса трудно ответить лучше.Вы должны предоставить образцы данных, а не только изображения, и показать нам, какой именно результат вы ожидаете в зависимости от выбора пользователя.
Но я надеюсь, что эта функция может помочь вам решить проблему.Я предположил, что если cost
не равно нулю, то мы в листе, иначе функция рекурсивно ищет подкомпоненты.
Редактировать:
Допустим,что seq = 14 было в евро, а не в фунтах стерлингов
update prod set curr = 'EUR' where seq = 14;
Как я уже сказал, точное решение зависит от того, какой результат вам нужен.Если вы знаете все возможные валюты, тогда вы можете изменить функцию для обработки валюты и отображать расходы, как показано здесь:
create or replace function calc_cost(i_comp in varchar2, i_curr in varchar2)
return number is
v_qty number := 0;
v_cost number := 0;
begin
select qty, cost into v_qty, v_cost from prod
where comp = i_comp and (curr = i_curr or curr is null);
if v_cost is null then
select sum(calc_cost(comp, i_curr)) into v_cost
from prod where part = i_comp and (curr = i_curr or curr is null);
end if;
return v_qty * nvl(v_cost, 0);
exception when no_data_found then
return 0;
end;
select seq, part, comp, qty, cost, curr,
calc_cost(comp, 'EUR') eur, calc_cost(comp, 'GBP') gbp
from prod
connect by part = prior comp
start with part = 'B';
SEQ PART COMP QTY COST CURR EUR GBP
----- ---- ---- ---------- ---------- ---- ---------- ----------
11 B B1 5 150 720
12 B1 B11 3 30 144
13 B11 B111 4 12 GBP 0 48
14 B11 B112 2 5 EUR 10 0
Part B
стоит 150 EUR и 720 GBP.
Вы можете найти все различные валюты в интересующей части данных, объединить их со своей таблицей и вызвать функцию таким образом.Результатом будет то, что для каждого seq
вы получите столько строк, сколько разных валют.Затем вы можете использовать listagg()
и представлять значения как 150 EUR; 720 GBP
в одной ячейке.
Вы также можете создать объект некоторого типа и изменить функцию, чтобы она возвращала таблицу кортежей (currency, cost_in_this_currency).Вопрос в том, как вы хотите показать данные.Или вы можете конвертировать значения в единую валюту, но для этого вам нужна ежедневная таблица коэффициентов.