我对SQL MAX()的理解是什么?

时间:2011-03-03 15:23:59

标签: mysql max

数据:( log_time是DATETIME类型)

log_id  | action      | log_time            | user
--------------------------------------------------
1         Processed     2011-02-28 16:38:48   1
2         Processed     2011-03-02 16:56:43   5
3         Processed     2011-03-02 17:00:17   5
4         Processed     2011-03-03 08:59:33   5

查询:

SELECT log_time, user 
FROM logs
WHERE action = "Processed"
GROUP BY action 
HAVING MAX(log_time)

结果:

log_time            | user
--------------------------
2011-02-28 16:38:48   1

显然,这根本没有最大log_time。如果我将查询更改为...

SELECT MAX(log_time), user 
FROM logs 
WHERE action = "Processed" 

然后我自然而然地得到了:

log_time            | user
--------------------------
2011-03-03 08:59:33   1

现在,我显然想要的数据是第4行:3月3日的数据,但是用户5.我知道我可以通过做一个简单的SELECT ... ORDER BY log_time DESC LIMIT 1来获得这个数据。但我的问题是,我对这些不正确的MAX()查询做了什么?在我看来,如果我使用HAVING MAX()运行查询,它会给我一行,好吧,有最大值。我不明白MAX()的工作原理是什么?

编辑:详细说明我的问题,基本上,当我看到一个查询...

SELECT * FROM logs WHERE action = "Processed"
GROUP BY action HAVING MAX(log_time)

...我的假设是,根据代码的显示方式,它将检索具有最大log_time的,其中action处理。这似乎是一个错误的假设。那么HAVING MAX()甚至意味着什么?

5 个答案:

答案 0 :(得分:4)

您需要为聚合函数包含GROUP BY子句。

SELECT MAX(log_time), user 
    FROM logs 
    WHERE action = "Processed" 
    GROUP BY user

或者,如果您要查找单个值,请不要包含用户:

SELECT MAX(log_time)
    FROM logs 
    WHERE action = "Processed" 

最后,如果您希望用户与该单个最大值相关联,请使用子查询

SELECT l.user, l.log_time
    FROM logs l
        INNER JOIN (SELECT MAX(log_time) as max_time
                        FROM logs 
                        WHERE action = "Processed") q
            ON l.log_time = q.max_time
                AND l.action = "Processed"

答案 1 :(得分:1)

基于其他人的输入,特别是Damien_The_Unbeliever,我意识到我的问题是HAVING MAX()实际上没有做任何事情。它只会将日期排除在外,因为它没有与任何东西进行比较。

当我说HAVING MAX(log_time)时,它转换为HAVING 2011-03-03 08:59:33,它不会告诉SQL它应该具有什么,它只是一个声明,如IF (5)。我认为。 HAVING对我来说仍然有些神秘,但我认为这就是为什么这个特殊问题让我感到悲伤的原因。

答案 2 :(得分:0)

我会按MAX(log_time)订购并选择前1名,因为无论如何都要进行排序。

答案 3 :(得分:0)

SELECT log_time, user 
FROM logs 
WHERE action = "Processed"  && log_time=(select MAX(log_time) from logs)
)

这给出了输出

2011-03-03 08:59:33 5

答案 4 :(得分:0)

HAVING - 子句用于不符合特定条件的过滤器组。您定义条件的方式是,“已处理”-group DOES与HAVING子句匹配,因为其MAX(log_time)包含最大log_time(或许HAVING MAX(log_time)计算结果为true。无论哪种方式,它都是一个奇怪的声明)......

你可能想要的是SELECT最大log_time,在这种情况下查询将是:

SELECT MAX(log_time), user 
FROM logs
WHERE action = "Processed"
GROUP BY action;

现在,您获得“1”作为用户的原因是用户列不是GROUP BY子句的一部分。这意味着MySQL不知道您在输出中需要哪个用户行。它可能是4行中的任何一行。因此,制定问题的另一种方法是:

SELECT logs.user, logs.log_time
FROM logs INNER JOIN 
  (SELECT MAX(log_time) as max, action
   FROM logs
   WHERE action = "Processed"
   GROUP BY action) sub ON logs.log_time = sub.max AND logs.action = sub.action

注意:根据标准SQL,您提供的SQL查询作为示例不是有效的SQL查询。它适用于mysql,但这要归功于MySQL /如何实现GROUP BY。在标准SQL中,您唯一可以选择的是GROUP BY子句中提到的聚合函数和/或列的结果。

因此,在其他数据库系统中,您将无法选择user - 列,因为它不是GROUP BY - 列而不是聚合函数的结果。为了使它成为有效的标准SQL,您必须编写:

SELECT MAX(log_time), user 
FROM logs
WHERE action = "Processed"
GROUP BY action, user -- Create groups based on both action AND user.
                      -- This allows us to SELECT the user column unambigiously.
;