Как и большинство других продуктов для реляционных баз данных, PostgreSQL поддерживает агрегатные функции . Агрегатная функция вычисляет один результат из нескольких входных строк. Например, существуют агрегаты для вычисления countsumavg(среднего), 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проверку.