Что я не понимаю в SQL MAX ()? - PullRequest
3 голосов
/ 03 марта 2011

Данные: (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 марта,но пользователь 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, когда обрабатывается действие.Это представляется ошибочным предположением.Что же тогда означает HAVING MAX()? 1031 *

Ответы [ 5 ]

4 голосов
/ 03 марта 2011

Вам нужно включить предложение 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 голос
/ 06 апреля 2011

Основываясь на мнении других, в частности Damien_The_Unbeliever, я понял, что моя проблема в том, что HAVING MAX() на самом деле ничего не делает.Он просто выведет дату, которая не работает, поскольку ее не сравнивают ни с чем.

Когда я говорю HAVING MAX(log_time), это переводится как HAVING 2011-03-03 08:59:33, что не говорит SQL о том, что он должен иметь, это просто утверждение, как IF (5).Я думаю.HAVING продолжает оставаться для меня загадкой, но я думаю, что именно по этой причине эта конкретная проблема вызывает у меня горе.

0 голосов
/ 03 марта 2011

В предложении HAVING используется фильтр ГРУПП, не соответствующий определенным критериям.Как вы определили критерии, «обработанная» группа 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 и не является результатом функции агрегирования.Для того чтобы он был действительным Standard 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.
;
0 голосов
/ 03 марта 2011
SELECT log_time, user 
FROM logs 
WHERE action = "Processed"  && log_time=(select MAX(log_time) from logs)
)

это дает вывод

2011-03-03 08:59:33 5

0 голосов
/ 03 марта 2011

Я бы сделал заказ по MAX (log_time) и выбрал бы верхнюю 1, поскольку сортировка все равно произойдет.

...