解析函数SUM返回具有相同值的窗口的平均值

时间:2018-12-14 12:34:41

标签: sql oracle analytic-functions

我正在尝试编写一个查询,该查询导致给定值的运行总和。但是,当将SUM用作分析函数时,我得到的结果是一个窗口内的平均值。

示例: 考虑以下查询:

with tbl as 
(
select 'steve' "NAME", 2000 val from dual UNION ALL
select 'john' "NAME", 4000 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 90 val from dual UNION ALL
select 'peter' "NAME", 450 val from dual UNION ALL
select 'hary' "NAME", 2772 val from dual UNION ALL
select 'may' "NAME", 2227.5 val from dual UNION ALL
select 'tom' "NAME", 500 val from dual UNION ALL
select 'sia' "NAME", 20000 val from dual
)
select name, val,
        sum(val) over (order by name) running_sum
from tbl;

结果:

enter image description here

我真正想要的是

enter image description here

我使用ROWNUM:

with tbl as 
(
select 'steve' "NAME", 2000 val from dual UNION ALL
select 'john' "NAME", 4000 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 90 val from dual UNION ALL
select 'peter' "NAME", 450 val from dual UNION ALL
select 'hary' "NAME", 2772 val from dual UNION ALL
select 'may' "NAME", 2227.5 val from dual UNION ALL
select 'tom' "NAME", 500 val from dual UNION ALL
select 'sia' "NAME", 20000 val from dual
)
select name, val,
        sum(val) over (order by rownum) running_sum
from tbl;

在第一个结果中显示的彼得的运行总和实际上是彼得总的运行总和的平均值。分析功能正在考虑为彼得提供一个窗口,因为我已在windowing子句中添加了“ NAME”。但是,为什么查询会导致窗口平均值而不是总和?

3 个答案:

答案 0 :(得分:2)

  

为什么查询会导致窗口平均值而不是总和?

这不是窗口的平均值。在您的rownum版本中,它显示的四个值分别是6270、6540、6630和7080-平均为6630。

这是一个连续的总和,但可能与您预期的不完全相同,并且显示输出的顺序使您实际上在应用的逻辑上有些困惑。

您可以通过对输出进行排序来查看数字的来源:

with tbl as 
(
select 'steve' "NAME", 2000 val from dual UNION ALL
select 'john' "NAME", 4000 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 90 val from dual UNION ALL
select 'peter' "NAME", 450 val from dual UNION ALL
select 'hary' "NAME", 2772 val from dual UNION ALL
select 'may' "NAME", 2227.5 val from dual UNION ALL
select 'tom' "NAME", 500 val from dual UNION ALL
select 'sia' "NAME", 20000 val from dual
)
select name, val,
        sum(val) over (order by name) running_sum
from tbl
order by name;

NAME         VAL RUNNING_SUM
----- ---------- -----------
hary        2772        2772
john        4000        6772
may       2227.5      8999.5
peter        450     10079.5
peter        270     10079.5
peter        270     10079.5
peter         90     10079.5
sia        20000     30079.5
steve       2000     32079.5
tom          500     32579.5

从窗口子句对它们的求值顺序来看,您现在可以看到运行总计。 peter的所有四个值都包含在每行的运行总计中-因为这就是order by中的所有内容-并将总计450 + 270 + 270 + 90 = 1080添加到以前的名字总共是8999.5。

通过包含基于行的window子句,您可以为每个peter行获得不同的值:

with tbl as 
(
select 'steve' "NAME", 2000 val from dual UNION ALL
select 'john' "NAME", 4000 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 90 val from dual UNION ALL
select 'peter' "NAME", 450 val from dual UNION ALL
select 'hary' "NAME", 2772 val from dual UNION ALL
select 'may' "NAME", 2227.5 val from dual UNION ALL
select 'tom' "NAME", 500 val from dual UNION ALL
select 'sia' "NAME", 20000 val from dual
)
select name, val,
        sum(val) over (order by name
          rows between unbounded preceding and current row) running_sum
from tbl;

NAME         VAL RUNNING_SUM
----- ---------- -----------
hary        2772        2772
john        4000        6772
may       2227.5      8999.5
peter        450      9449.5
peter        270      9719.5
peter        270      9989.5
peter         90     10079.5
sia        20000     30079.5
steve       2000     32079.5
tom          500     32579.5

对相同名称的行进行求值的顺序仍然不确定,因为该分析子句中没有有关如何断开关系的指令。

现在,对整个结果进行隐式排序(至少在今天,使用CTE以及我的版本和优化器的决定),这可能不是您想要的;但是无论顺序如何,无论如何您都应该有一个明确的order by

答案 1 :(得分:0)

检查我的答案。

我为row_number添加了一个子查询并对其进行了排序

with tbl as 
(
select 'steve' name, 2000 val from dual UNION ALL
select 'john' "NAME", 4000 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 270 val from dual UNION ALL
select 'peter' "NAME", 90 val from dual UNION ALL
select 'peter' "NAME", 450 val from dual UNION ALL
select 'hary' "NAME", 2772 val from dual UNION ALL
select 'may' "NAME", 2227.5 val from dual UNION ALL
select 'tom' "NAME", 500 val from dual UNION ALL
select 'sia' "NAME", 20000 val from dual
), tbl2 as
(
  select row_number() over (order by 1) rn, tbl.* from tbl
)
select name, val,
        sum(val) over (order by rn) running_sum
from tbl2;

答案 2 :(得分:0)

因此,实际发生的情况是,分析函数首先汇总一个窗口的总和,在这种情况下,彼得的总和为1080,然后将结果加到前面的总和中,即8999.5,最后显示总和(1080 +窗口中的每一行都为8999.5 = 10079.5)。

与窗口的平均值无关。