如何让MIN,MAX,AVG使用内连接?

时间:2017-10-21 20:31:44

标签: mysql

我需要从数据集中获取每种行业类型的平均值,最小值和最大值。当我使用MIN,MAX,AVG函数时,它只返回与Amount列相同的值。

我的尝试

SELECT c.Custid, c.Cname, c.City, c.IndustryType, o.OrderNo, o.OrderDate, o.SalesPersonID, o.Amount, 
AVG(o.Amount) AS 'Average Amount',
MIN(o.Amount) AS 'Minimum Amount',
MAX(o.Amount) AS 'Maximum Amount'
FROM customer c
INNER JOIN orders o
ON c.custid = o.custid
GROUP BY c.IndustryType,o.orderdate;

1 个答案:

答案 0 :(得分:0)

SQL标准要求GROUP BY子句包含 ALL NOT 使用aggregate function的列(即min(),max( ),avg()等。)。

  

SQL92及更早版本不允许选择列表的查询,   HAVING条件或ORDER BY列表指的是非聚合列   未在GROUP BY子句中命名。   https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

然而,MySQL为GROUP BY实现了非标准的附加功能,而在旧版本的MySQL中,它违反了非标准方法。 (有一个服务器设置,您可以更改为从标准语法转换为非标准语法进行分组。)自MySQL 5.7.5起,默认设置已更改为SQL标准方法。

  

MySQL 5.7.5及更高版本实现了对功能依赖的检测。如果   启用ONLY_FULL_GROUP_BY SQL模式(默认情况下是这样),   MySQL拒绝选择列表,HAVING条件或的查询   ORDER BY列表引用既未命名的非聚合列   GROUP BY子句在功能上也不依赖于它们。

请参阅:ONLY_FULL_GROUP_BY

几乎可以肯定,原始查询不起作用的原因是出于上述考虑。许多人会告诉你,使用非标准方法是不好的做法,事实上,如果你进一步研究这个话题,你会发现非标准方法会返回"不确定结果"对于未包含在group by子句中的所有列(除极少数情况外)。你总是更好地使用标准方法。 e.g。

SELECT
      c.IndustryType
    , o.OrderDate
    , AVG(o.Amount) AS "Average Amount"
    , MIN(o.Amount) AS "Minimum Amount"
    , MAX(o.Amount) AS "Maximum Amount"
FROM customer c
INNER JOIN orders o ON c.custid = o.custid
GROUP BY
      c.IndustryType
    , o.OrderDate
;

SELECT
      c.Custid
    , c.Cname
    , c.City
    , c.IndustryType
    , o.OrderNo
    , o.OrderDate
    , o.SalesPersonID
    , o.Amount
    , AVG(o.Amount) AS "Average Amount"
    , MIN(o.Amount) AS "Minimum Amount"
    , MAX(o.Amount) AS "Maximum Amount"
FROM customer c
INNER JOIN orders o ON c.custid = o.custid
GROUP BY
      c.Custid
    , c.Cname
    , c.City
    , c.IndustryType
    , o.OrderNo
    , o.OrderDate
    , o.SalesPersonID
    , o.Amount
;

值得一提的是,您的原始查询似乎想要为(IndustryType& OrderDate)的每个唯一组合计算聚合,但要在多个细节行上重复这些聚合。有"窗口功能"允许发生这种情况正在开发中并打算与MySQL 8.x一起发布,这些函数已存在于其他数据库中,例如DB2,Oracle,SQL Server,Postgre,SQL Lite,MariaDB(及更多)。

窗口化聚合的语法如下所示:

SELECT
      c.Custid
    , c.Cname
    , c.City
    , c.IndustryType
    , o.OrderNo
    , o.OrderDate
    , o.SalesPersonID
    , o.Amount
    , AVG(o.Amount) OVER(PARTITION BY c.IndustryType, o.OrderDate)
        AS "Average Amount" 
    , MIN(o.Amount) OVER(PARTITION BY c.IndustryType, o.OrderDate)
        AS "Minimum Amount"
    , MAX(o.Amount) OVER(PARTITION BY c.IndustryType, o.OrderDate)
        AS "Maximum Amount"
FROM customer c
INNER JOIN orders o ON c.custid = o.custid