Почему я должен использовать агрегаторы при использовании функции MIN/MAX

#sql #postgresql #aggregate-functions

Вопрос:

Я хочу получить MIN значение из столбца и соответствующее date

 SELECT date, MIN(speed) FROM foo 
    INNER JOIN bar
        ON foo.id = bar.foo_id;
 

Это не работает

Дата столбца должна использоваться в ГРУППЕ ПО или в другой агрегатной функции

Я не понимаю, почему я не могу выбрать дату, где MIN(speed) находится. Он в той же строке, просто еще один атрибут…

Ответ №1:

Причина, по которой вы не можете делать то, что хотите, заключается в том, что SQL определяется не так. Я не думаю, что ваша версия была бы очень полезной. В конце концов, что бы сделал ваш запрос, если бы вы это сделали AVG(speed) ? Или и MIN(speed) то и другое и MAX(speed) ?

В любом случае, то, что вы хотите сделать, достаточно просто с помощью ORDER BY :

 SELECT date, speed
FROM foo JOIN
     bar
     ON foo.id = bar.foo_id
ORDER BY speed
LIMIT 1;
 

Ответ №2:

Я не понимаю, почему я не могу выбрать дату, где MIN(скорость)

Агрегатная функция уменьшает количество строк до одной строки. Результат min(speed) без ГРУППЫ ПО (как вы его использовали) дает одно значение (и строку), но у вас будет несколько значений для date столбца

Сообщение об ошибке говорит вам, что Postgres не просто выберет для вас случайное значение, и вам нужно указать какое-то правило, чтобы выбрать нужное значение даты или комбинацию даты и скорости.

Комментарии:

1. Теперь я это понимаю. Я не знал, что MIN() это агрегатор — и я думаю, что в этом нет особого смысла (насколько мне известно). Потому что зачем вам агрегировать, когда требуется минимальное значение? Это можно легко сделать, просто сказав: «это строка с минимальным значением». Но, может быть, это потому, что Postgres каким-то образом работает внутренне так, как я не понимаю, и именно поэтому это делается так.

2. @Stophface: ну, вот как определяется «агрегат» в SQL — он сводит множество строк к одной строке, например sum() , ведет себя одинаково.

Ответ №3:

Как указано в сообщении об ошибке, вам необходимо включить date столбец в GROUP BY :

 SELECT  date,
        MIN(speed)
  FROM foo 
    INNER JOIN bar ON foo.id = bar.foo_id
  GROUP BY date;