具有相同值的 window 的解析函数 SUM returns 平均值

Analytic Function SUM returns Average for window with same values

我试图编写一个查询,结果是给定值的 运行 总和。但是,当应用 SUM 作为分析函数时,我得到的结果的平均值在 window.

范围内

示例: 考虑以下查询:

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;

结果:

我真正想要的是

我使用 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;

第一个结果中显示的 peter running_sum 实际上是 peter 总 running_sum 的平均值。分析函数正在考虑对 peter 使用 window,因为我在 windowing 子句中包含了 "NAME"。但为什么查询结果是 window 的平均值而不是 运行 总和?

检查我的回答。

我为 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;

why is the query resulting in average for the window instead of running sum?

这不是 window 的平均值。在您的 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

您可以看到 运行 总计现在有意义,从它们被 windowing 子句评估的顺序来看。 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 不管它是什么。

所以,实际发生的是分析函数首先聚合 window 的总计,在本例中为 peter,即 1080,然后将结果添加到前面的行总计 8999.5,最后显示 window.

中每行的总数 (1080 + 8999.5 = 10079.5)

与 window 的平均值无关。