Oracle SQL/PLSQL:基于货币拆分和求和值的分层查询
Oracle SQL/PLSQL: Hierarchical query to split and sum value based on currency
运气好的话我可以描述我的要求而不会让自己感到困惑...
我有一个多级数据集,用户可以在其中标记要汇总到不同总计中的记录。
数据输入规则:
- IF 'Base Unit' 列 (True/False) 被选中(即 True),然后 'Add for Option #' 和 'Remove for Option #' 必须为 NULL。
- 如果设置了 'Add for Option #' 或 'Remove for Option #',则 'Base Unit' 列必须为 FALSE。
- IF 'Add for Option #' 则设置;选项列表(字母 A-Z,以分号分隔)不能包含在不同级别的相同结构中的字母(例如,对于序列号 = 300,'Add for Option #' 不能包括 'B' 或'D'。相同的规则适用于 'Remove for Option #' 列。
例如,- IF 'Add for Option #' 或 'Remove for Option #' 则同一行不能包含相同的选项(即字母);对于序列号 = 300,'Add for Option #' 不能包括 'B' 或 'D'.
'Purch Cost/Curr' 列仅为每个结构的最低级别填充 - 这些值已经乘以数量。
我需要一个 PLSQL 函数,它将:
- 根据参数 (is_base_
/ option_
),查找 'Base Unit' 列 = is_base_
或('Add for Option #' 列或 'Remove for Option #' 列的所有行包含 option_
)。例如:
select sequence_no,
part_no,
component_part,
base_unit
add_for_option,
remove_for_option
from prod_conf_cost_struct
where (base_unit = is_base_ and base_unit = 'True'
or (add_for_option = option_ or remove_for_option = option_));
遍历上述查询返回的所有行并汇总 PER CURRENCY 结构中每个级别的 'Purch Cost/Curr' 列的总数.我面临的主要挑战是,一旦我有了第 2 级行的总数,我就无法在继续结构之前将其乘以该级别的 'Qty'。
- 如果计算选项的总数,则必须从 'Add for Option #' 值中减去 'Remove for Option #' 值。
Here is my NEW attempt:
function calc_cost(
model_no_ number,
revision_ number,
sequence_no_ in number,
currency_ in varchar2
) return number is
qty_ number := 0;
cost_ number := 0;
begin
select nvl(new_qty, qty), purch_cost
into qty_, cost_
from prod_conf_cost_struct_clv
where model_no = model_no_
and revision = revision_
and sequence_no = sequence_no_
and (purch_curr = currency_ or purch_curr is null);
if cost_ is null then
select sum(calc_cost(model_no, revision, sequence_no, purch_curr)) into cost_
from prod_conf_cost_struct_clv
where model_no = model_no_
and revision = revision_
and (purch_curr = currency_ or purch_curr is null)
and part_no in (
select component_part
from prod_conf_cost_struct_clv
where model_no = model_no_
and revision = revision_
and sequence_no = sequence_no_);
end if;
return qty_ * cost_;
exception when no_data_found then
return 0;
end calc_cost;
除了 'Sequence No' 列之外,还有 'Model No' 和 'Revision'。
MODEL_NO - REVISION - SEQUENCE_NO
将构成组合键。
select level, sys_connect_by_path(sequence_no, '->') path,
calc_cost(model_no, revision, sequence_no, 'GBP') total_gbp,
calc_cost(model_no, revision, sequence_no, 'EUR') total_eur,
calc_cost(model_no, revision, sequence_no, 'USD') total_usd
calc_cost(model_no, revision, sequence_no, '???') total_other
from prod_conf_cost_struct_clv
where model_no = 35
and revision = 2
connect by prior component_part = part_no
and prior model_no = 30
and prior revision = 2
start with sequence_no = 22500
order by sequence_no
我需要像这样汇总的每种货币的总计(当 Base/Option 列为空白时,它将在 BASE_UNIT = True
时汇总):
恐怕你们把大家弄糊涂了:)
虽然您的要求部分难以理解,但我认为如果我必须处理这样的任务,我会做一件事。我会编写递归函数来计算从树的任何部分到叶子的成本。
下面是类似你的数据的演示:
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
不为 null 那么我们在叶中,否则函数递归地查找子组件。
编辑:
Lets say that seq = 14 was in EUR not GBP
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
零件 B
的价格为 150 欧元和 720 英镑。
您可以在数据的有趣部分找到所有不同的货币,将它们与您的 table 连接起来,然后以这种方式调用函数。结果将是,对于每个 seq
,您将获得与不同货币一样多的行。然后您可以使用 listagg()
并在一个单元格中将值显示为 150 EUR; 720 GBP
。
您还可以创建一些类型对象并将函数修改为 return table 元组(货币,cost_in_this_currency)。问题是你想如何显示数据。或者您可以将价值转换为通用货币,但为此您需要每日 table 比率。
运气好的话我可以描述我的要求而不会让自己感到困惑...
我有一个多级数据集,用户可以在其中标记要汇总到不同总计中的记录。
数据输入规则:
- IF 'Base Unit' 列 (True/False) 被选中(即 True),然后 'Add for Option #' 和 'Remove for Option #' 必须为 NULL。
- 如果设置了 'Add for Option #' 或 'Remove for Option #',则 'Base Unit' 列必须为 FALSE。
- IF 'Add for Option #' 则设置;选项列表(字母 A-Z,以分号分隔)不能包含在不同级别的相同结构中的字母(例如,对于序列号 = 300,'Add for Option #' 不能包括 'B' 或'D'。相同的规则适用于 'Remove for Option #' 列。 例如,
- IF 'Add for Option #' 或 'Remove for Option #' 则同一行不能包含相同的选项(即字母);对于序列号 = 300,'Add for Option #' 不能包括 'B' 或 'D'.
'Purch Cost/Curr' 列仅为每个结构的最低级别填充 - 这些值已经乘以数量。
我需要一个 PLSQL 函数,它将:
- 根据参数 (is_base_
/ option_
),查找 'Base Unit' 列 = is_base_
或('Add for Option #' 列或 'Remove for Option #' 列的所有行包含 option_
)。例如:
select sequence_no,
part_no,
component_part,
base_unit
add_for_option,
remove_for_option
from prod_conf_cost_struct
where (base_unit = is_base_ and base_unit = 'True'
or (add_for_option = option_ or remove_for_option = option_));
遍历上述查询返回的所有行并汇总 PER CURRENCY 结构中每个级别的 'Purch Cost/Curr' 列的总数.我面临的主要挑战是,一旦我有了第 2 级行的总数,我就无法在继续结构之前将其乘以该级别的 'Qty'。
- 如果计算选项的总数,则必须从 'Add for Option #' 值中减去 'Remove for Option #' 值。
Here is my NEW attempt:
function calc_cost(
model_no_ number,
revision_ number,
sequence_no_ in number,
currency_ in varchar2
) return number is
qty_ number := 0;
cost_ number := 0;
begin
select nvl(new_qty, qty), purch_cost
into qty_, cost_
from prod_conf_cost_struct_clv
where model_no = model_no_
and revision = revision_
and sequence_no = sequence_no_
and (purch_curr = currency_ or purch_curr is null);
if cost_ is null then
select sum(calc_cost(model_no, revision, sequence_no, purch_curr)) into cost_
from prod_conf_cost_struct_clv
where model_no = model_no_
and revision = revision_
and (purch_curr = currency_ or purch_curr is null)
and part_no in (
select component_part
from prod_conf_cost_struct_clv
where model_no = model_no_
and revision = revision_
and sequence_no = sequence_no_);
end if;
return qty_ * cost_;
exception when no_data_found then
return 0;
end calc_cost;
除了 'Sequence No' 列之外,还有 'Model No' 和 'Revision'。
MODEL_NO - REVISION - SEQUENCE_NO
将构成组合键。
select level, sys_connect_by_path(sequence_no, '->') path,
calc_cost(model_no, revision, sequence_no, 'GBP') total_gbp,
calc_cost(model_no, revision, sequence_no, 'EUR') total_eur,
calc_cost(model_no, revision, sequence_no, 'USD') total_usd
calc_cost(model_no, revision, sequence_no, '???') total_other
from prod_conf_cost_struct_clv
where model_no = 35
and revision = 2
connect by prior component_part = part_no
and prior model_no = 30
and prior revision = 2
start with sequence_no = 22500
order by sequence_no
我需要像这样汇总的每种货币的总计(当 Base/Option 列为空白时,它将在 BASE_UNIT = True
时汇总):
恐怕你们把大家弄糊涂了:)
虽然您的要求部分难以理解,但我认为如果我必须处理这样的任务,我会做一件事。我会编写递归函数来计算从树的任何部分到叶子的成本。
下面是类似你的数据的演示:
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
不为 null 那么我们在叶中,否则函数递归地查找子组件。
编辑:
Lets say that seq = 14 was in EUR not GBP
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
零件 B
的价格为 150 欧元和 720 英镑。
您可以在数据的有趣部分找到所有不同的货币,将它们与您的 table 连接起来,然后以这种方式调用函数。结果将是,对于每个 seq
,您将获得与不同货币一样多的行。然后您可以使用 listagg()
并在一个单元格中将值显示为 150 EUR; 720 GBP
。
您还可以创建一些类型对象并将函数修改为 return table 元组(货币,cost_in_this_currency)。问题是你想如何显示数据。或者您可以将价值转换为通用货币,但为此您需要每日 table 比率。