【问题标题】:Oracle SQL running total on change of field (SUM on column only when field changes)Oracle SQL 在字段更改时运行总计(仅在字段更改时对列求和)
【发布时间】:2018-01-17 20:24:35
【问题描述】:

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

以下表为例:

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

选择 X.A、Y.B
来自 X
在 X.DATE = Y.DATE 和 X.VAL1 = 上的内部连接 ​​Y 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

我试图在一个简单的查询中做到这一点。我可以使用特定的功能来执行此操作吗?

【问题讨论】:

  • 是否可能有两行 A 的值相同但 B 的值不同?
  • @Aleksej 不,B 的值将始终相同。重复项来自 A。请注意,A 列是一个表,B 列是另一个表

标签: sql oracle


【解决方案1】:

对于提供的简单数据集,以下应该有效。当然,您需要查看 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 中还涉及到窗口子句,因为您指定了需要运行总计。

【讨论】:

    【解决方案2】:

    咩咩?

    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>
    

    【讨论】:

      【解决方案3】:

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

      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 行

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-12-25
        • 2011-07-02
        • 2017-02-01
        • 1970-01-01
        • 2012-11-04
        • 2012-02-16
        • 2010-10-29
        相关资源
        最近更新 更多