Как и большинство других продуктов для реляционных баз данных, PostgreSQL поддерживает агрегатные функции . Агрегатная функция вычисляет один результат из нескольких входных строк. Например, существуют агрегаты для вычисления count
, sum
, avg
(среднего), max
(максимума) и min
(минимума) по набору строк.
В качестве примера, мы можем найти самые высокие показания при низкой температуре в любом месте с помощью:
SELECT max(temp_lo) FROM weather;
max
-----
46
(1 row)
Если бы мы хотели узнать, в каком городе (или городах) произошло чтение, мы могли бы попробовать:
SELECT city FROM weather WHERE temp_lo = max(temp_lo); WRONG
но это не сработает, так как агрегат max
нельзя использовать в WHERE
предложении. (Это ограничение существует, потому что WHERE
предложение определяет, какие строки будут включены в вычисление агрегации, поэтому очевидно, что оно должно быть оценено до того, как будут вычислены агрегатные функции.) Однако, как это часто бывает, запрос может быть переформулирован для получения желаемого результата. здесь с помощью подзапроса :
SELECT city FROM weather
WHERE temp_lo = (SELECT max(temp_lo) FROM weather);
city
---------------
San Francisco
(1 row)
Это нормально, потому что подзапрос — это независимое вычисление, которое вычисляет собственный агрегат отдельно от того, что происходит во внешнем запросе.
Агрегаты также очень полезны в сочетании с GROUP BY
предложениями. Например, мы можем получить максимальную низкую температуру, наблюдаемую в каждом городе, с помощью:
SELECT city, max(temp_lo)
FROM weather
GROUP BY city;
city | max
---------------+-----
Hayward | 37
San Francisco | 46
(2 rows)
что дает нам одну выходную строку для каждого города. Каждый совокупный результат вычисляется по строкам таблицы, соответствующим этому городу. Мы можем отфильтровать эти сгруппированные строки, используя HAVING
:
SELECT city, max(temp_lo)
FROM weather
GROUP BY city
HAVING max(temp_lo) < 40;
city | max
---------+-----
Hayward | 37
(1 row)
что дает нам те же результаты только для городов, у которых все temp_lo
значения ниже 40. Наконец, если нас интересуют только города, названия которых начинаются с « S
» , мы могли бы сделать:
SELECT city, max(temp_lo)
FROM weather
WHERE city LIKE 'S%' -- (1)
GROUP BY city
HAVING max(temp_lo) < 40;
(1) | Оператор LIKE выполняет сопоставление с образцом и объясняется в Разделе 9.7 . |
Важно понимать взаимодействие между агрегатами и операторами SQL и предложениями. Фундаментальное различие между и заключается в следующем: выбирает входные строки до того, как будут вычислены группы и агрегаты (таким образом, он контролирует, какие строки попадают в агрегатные вычисления), тогда как выбирает групповые строки после вычисления групп и агрегатов. Таким образом, предложение не должно содержать агрегатных функций; нет смысла пытаться использовать агрегат, чтобы определить, какие строки будут входными данными для агрегатов. С другой стороны, предложение всегда содержит агрегатные функции. (Строго говоря, вам разрешено писатьWHEREHAVINGWHEREHAVINGWHEREHAVINGWHEREHAVINGHAVING
предложение, в котором не используются агрегаты, но оно редко бывает полезным. Это же условие можно было бы использовать более эффективно на WHERE
этапе.)
В предыдущем примере мы можем применить ограничение на название города в WHERE
, так как для него не требуется агрегат. Это более эффективно, чем добавление ограничения на HAVING
, потому что мы избегаем группировки и агрегирования всех строк, не прошедших WHERE
проверку.
0 комментариев