Oracle SQL 在字段更改时运行总计(仅在字段更改时对列运行 SUM)

  • 本文关键字:运行 字段 SUM SQL Oracle sql oracle
  • 更新时间 :
  • 英文 :


我有一个关于如何仅在字段更改时对列求和的问题。

以下表为例:

请注意,列 A 列和列 B 是不同的表。 即从表 X 中选择 A,从表 Y 中选择 B



X.DATE = Y.DATE 和 X.VAL1 = 上从 X 内部联接 Y 中选择 X.A、Y.B Y.VAL1 和 X.VAL2 = Y.VAL2

A     B
123    5
123    5
456    10
789    15
789    15

我需要对 A 列字段更改的 B 列求和:

即查询应返回 5 + 10+ 15 = 30(第一次为 5,因为 A 列中的值为 123,第二次返回 10,因为 A 列从 123 更改为 456 - 请注意,跳过第二行是因为 A 列仍然包含值 123 - 因此字段逻辑的变化等等)。

我不能做一个简单的SUM(B),因为这会返回50。我也不能做SUM(B) OVER (PARTITION BY A)因为这会按组进行汇总,而不是通过更改字段。

我的输出需要如下所示:

A    B    X
123  5    5
123  5    5
456  10   15
789  15   30
789  15   30

我正在尝试在一个简单的查询中执行此操作。是否有我可以使用的特定功能来执行此操作?

对于提供的简单数据集,以下内容应该有效。当然,您需要查看ORDER BY子句在确切用例中的正确性。

SELECT a
,b
,SUM(CASE WHEN a = prev_a THEN 0 ELSE b END) OVER (ORDER BY a RANGE UNBOUNDED PRECEDING) AS x
FROM (
SELECT a
,b
,LAG(a) OVER (ORDER BY a) AS prev_a
FROM {your_query}
)

此解决方案使用LAG函数,该函数返回上一个结果中的指定列。然后,仅当上一行的值不同时,外部查询的SUM才会给出值。SUM中还涉及窗口子句,因为您指定需要汇总。

Ta-daaa?

SQL> with test (a, b) as
2  (select 123, 5 from dual union all
3   select 123, 5 from dual union all
4   select 456, 10 from dual union all
5   select 789, 15 from dual union all
6   select 789, 15 from dual
7  ),
8  proba as(
9  select a, b,
10    case when a <> nvl(lag(a) over (order by a), 0) then 'Y' else 'N' end switch
11  from test
12  )
13  select a, b,
14    sum(decode(switch, 'Y', b, 0)) over (partition by null order by a) x
15  from proba
16  order by a;
A          B          X
---------- ---------- ----------
123          5          5
123          5          5
456         10         15
789         15         30
789         15         30
SQL>

你也可以创建一个函数并使用它,见下面的示例,

create package test_pkg123
as
a number;
r_sum NUMBER;
function get_r_sum(p_a number, p_val NUMBER, rown NUMBER) return number;
end;
/
create or replace package body test_pkg123
as
function get_r_sum(p_a number, p_val NUMBER, rown NUMBER) return number
is
begin
if rown = 1 then
r_sum := p_val;
return r_sum;
end if;
if p_a != a then
r_sum := nvl(r_sum, 0) + nvl(p_val, 0);
end if;
a := p_a;
return r_sum;
end;
end;
/
with test (a, b) as
(select 123, 5 from dual union all
select 123, 5 from dual union all
select 456, 10 from dual union all
select 789, 15 from dual union all
select 789, 15 from dual union all
select 789, 15 from dual union all
select 123, 2 from dual
)
select a, b, test_pkg123.get_r_sum(a, b, rownum) r_sum 
from test;

输出:

A          B      R_SUM
123          5          5
123          5          5
456         10         15
789         15         30
789         15         30
789         15         30
123          2         32

已选择 7 行

最新更新