Aggregate Functions
GROUP BY (covered next in this series) once you need one summary value per group rather than one summary value overall.The essentials
Function | Returns |
|---|---|
| Number of rows |
| Number of non-NULL values in |
| Total of all values in |
| Average of all values in |
| Smallest value in |
| Largest value in |
| All values of |
| All values of |
COUNT, SUM, AVG, MIN, and MAX over all orders
SELECT COUNT(*) AS order_count,
SUM(total_amount) AS revenue,
AVG(total_amount) AS avg_order_value,
MIN(total_amount) AS smallest_order,
MAX(total_amount) AS largest_order
FROM orders;order_count | revenue | avg_order_value | smallest_order | largest_order
------------+----------+-----------------+-----------------+---------------
842 | 61350.75 | 72.86 | 9.99 | 499.00ARRAY_AGG and STRING_AGG
These two are PostgreSQL specialties — genuinely convenient aggregates that are not as universally available in other database systems.
All product names in a single order, as an array
SELECT o.order_id, ARRAY_AGG(p.name) AS products FROM order_items oi JOIN orders o ON o.order_id = oi.order_id JOIN products p ON p.product_id = oi.product_id WHERE o.order_id = 1042 GROUP BY o.order_id;
order_id | products
---------+--------------------------------
1042 | {"Wireless Mouse","USB-C Cable"}The same thing as a readable, comma-separated string
SELECT o.order_id, STRING_AGG(p.name, ', ') AS products FROM order_items oi JOIN orders o ON o.order_id = oi.order_id JOIN products p ON p.product_id = oi.product_id WHERE o.order_id = 1042 GROUP BY o.order_id;
order_id | products
---------+---------------------------
1042 | Wireless Mouse, USB-C CableSTRING_AGG also accepts an ORDER BY inside the function call (for example STRING_AGG(p.name, ', ' ORDER BY p.name)) so you can control the order items appear in, independent of the query’s own ORDER BY.NULL values rather than treating them as zero or including them in the count. AVG(discount) over a column where most rows have no discount recorded (NULL) averages only the rows that actually have a value — it does not divide by the total row count. The one exception is COUNT(*), which counts rows regardless of any column’s value.Aggregates without GROUP BY summarize everything
GROUP BY clause, PostgreSQL treats the entire result set as a single group and returns exactly one row.One row summarizing the whole products table
SELECT COUNT(*) AS total_products, AVG(price) AS avg_price FROM products;
Aggregate functions reduce many rows down to one value
COUNT, SUM, AVG, MIN, MAX are the universal building blocks
ARRAY_AGG and STRING_AGG are PostgreSQL-specific and very convenient
All aggregates ignore NULLs, except COUNT(*)
Without GROUP BY, an aggregate summarizes the entire result set into one row