MySQL使用COUNT()的MAX(),得到错误的聚合值

时间:2014-09-08 22:13:28

标签: mysql sql aggregate-functions

我有一个复杂的查询,我会在这里简化以便演示我的问题。

通常,对于调度应用程序,我试图计算同时发生的记录(点数)(以15分钟为间隔),因此我将其分组。每个15分钟的块都有一个与之关联的特定计算列值(age_value)。例如:

+------------+-------+-------+-----------+
| date       | start | spots | age_value |
+------------+-------+-------+-----------+
| 2013-08-05 |   950 |    15 |   1060701 |
| 2013-08-05 |   975 |    15 |   1060701 |
| 2013-08-05 |  1000 |    15 |   1060701 |
| 2013-08-05 |  1025 |    15 |   1060701 |
| 2013-08-05 |  1050 |    14 |   1060700 |
..........................................
| 2013-08-05 |  1275 |    14 |   1060700 |
| 2013-08-05 |  1300 |    12 |   1050600 |
| 2013-08-05 |  1325 |    12 |   1050600 |
..........................................
| 2013-08-05 |  1700 |    12 |   1050600 |
| 2013-08-05 |  1725 |    12 |   1050600 |
| 2013-08-05 |  1750 |    12 |   1050600 |
| 2013-08-05 |  1775 |    12 |   1050600 |
+------------+-------+-------+-----------+

现在,这是一个子查询。在它周围我有另一个查询来获取斑点数量的MAX。即在特定时间段内(在这种情况下为9:30 - 18:00)占用的最大点数是多少。

现在是出错的重要部分:我想获得具有最高值的记录的age_value。在这种情况下1060701.然而,问题似乎是它总是会返回子查询中第一行的age_value。在示例情况下,这是正确的,因为第一行也是具有最高点数的行。但情况并非总是如此!

最好的方法是什么?在点DESC上对子查询进行ORDER BY感觉很脏,这使得具有最高点的行始终位于顶部。

我的(简化)查询:

SELECT subq.date, MAX(subq.spots) AS max_spots, age_value
FROM (
    SELECT  di.date, 
            ts.start,
            COUNT(*) AS spots,
            SUM(POW(10, ...)) AS age_value
    FROM date_intervals di
        JOIN occupancy_caches oc ON oc.date = di.date
        JOIN time_slices ts ON ts.start < oc.end AND ts.start >= oc.start
    AND ts.start BETWEEN 950 AND 1775
    GROUP BY ts.start, di.date
) subq
GROUP BY subq.date

1 个答案:

答案 0 :(得分:2)

您正在使用documentation明确警告不要使用的MySQL扩展。您应该确保聚合查询的select中的所有列都是聚合函数或group by子句的参数 - 除非您确实非常确定您正在做什么。< / p>

在您的情况下,您可以使用substring_index() / group_concat()技巧获得您想要的内容:

SELECT subq.date, MAX(subq.spots) AS max_spots,
       substring_index(group_concat(age_value order by subq.spots desc), ',', 1) as age_value
FROM (SELECT  di.date, ts.start, COUNT(*) AS spots, SUM(POW(10, ...)) AS age_value
      FROM date_intervals di JOIN
           occupancy_caches oc
           ON oc.date = di.date JOIN
           time_slices ts
           ON ts.start < oc.end AND ts.start >= oc.start AND ts.start BETWEEN 950 AND 1775
      GROUP BY ts.start, di.date
     ) subq
GROUP BY subq.date;