为什么MySQL中需要sum()函数?

问题描述 投票:0回答:1

我正在做“Murach's MySQL 第三版”的练习,它给出了以下提示:

“11. 编写一条 SELECT 语句,使用聚合窗口函数来计算发票总额总和的移动平均值。返回这些列:

  • 发票表中发票日期的月份
  • 发票表中发票总额的总和
  • 按发票月份排序的发票总额的移动平均值

结果集应按发票月份和框架进行分组 移动平均线应包括当前行加上之前的三行 当前行。”

所引用的发票表如下所示(总共 114 行):

发票_id 供应商_id 发票号码 发票日期 发票_总计 付款_总计 信用总额 terms_id 发票到期日期 付款日期
1 122 989319-457 2018-04-08 3813.33 3813.33 0 3 2018-05-08 2018-05-07

我最初想出的解决方案是这样的:

SELECT
    EXTRACT(MONTH FROM invoice_date) AS months, 
    SUM(invoice_total) AS invoice_total_sum,
    AVG(invoice_total) OVER(
        ORDER BY EXTRACT(MONTH FROM invoice_date)
        ROWS 3 PRECEDING
    ) AS rolling_avg
FROM
    invoices
GROUP BY
    months;

当我运行此程序时,出现以下错误:

Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'ap.invoices.invoice_total' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

查看作者提供的解决方案并重新阅读问题后,我意识到我应该取每月金额的平均值,而不仅仅是发票本身的平均值。所以真正的解决方案是这样的:

SELECT
    EXTRACT(MONTH FROM invoice_date) AS months, 
    SUM(invoice_total) AS invoice_total_sum,
    AVG(SUM(invoice_total)) OVER( # why does this need the SUM() function?
        ORDER BY EXTRACT(MONTH FROM invoice_date)
        ROWS 3 PRECEDING
    ) AS rolling_avg
FROM
    invoices
GROUP BY
    months;

这会产生一个像这样的输出表(有 5 行):

发票总金额 滚动平均
4 5828.18 5828.180000

但是,我不明白的是为什么第一个解决方案无法运行。我知道为什么这不是练习所寻找的内容,但我不明白是什么导致它出错。

我的理解是,像

sum()
avg()
这样的聚合函数给出有关“函数依赖”的错误的原因是,否则你会得到不一致数量的输出行。如果我尝试仅使用
sum(invoice_total)
invoice_date
,它将生成一行用于求和,并生成许多行用于日期,并且无法将它们解析为输出表(不更改 only_full_group_by 模式)。但平均函数也是一个聚合函数,那么为什么它不按照
group by
子句的指定,对每个月的所有发票总额进行平均呢?

sql mysql aggregate-functions window-functions
1个回答
0
投票

(1)

AVG
是一个聚合函数,但这里它与
OVER
子句一起使用,使其成为窗口函数。使用窗口函数,结果显示在每一行上。而使用常规聚合函数,它会组合多行并将结果显示在一行上。

在您的查询中,您可以像下面一样删除

SUM
,并且可以看到
AVG
的分组仅适用于当前行和前 3 行;结果显示在每一行

SELECT
    EXTRACT(MONTH FROM invoice_date) AS months,
    invoice_date, 
    AVG(invoice_total) OVER(
        ORDER BY EXTRACT(MONTH FROM invoice_date)
        ROWS 3 PRECEDING
    ) AS rolling_avg
FROM
    invoices
ORDER BY EXTRACT(MONTH FROM invoice_date)

(2) 你的下一个问题是为什么

SUM(invoice_total)
位于
AVG
内部。 这里,AVG 函数正在对已按 EXTRACT(MONTH FROM Invoice_date) 分组的行进行求和。在窗口函数内部,分组的行按 ORDER BY 排序,以便当前行回顾过去 3 个 SUM 行(过去 3 个月)以获得
AVG

希望这有帮助

© www.soinside.com 2019 - 2024. All rights reserved.