PostgreSQL does not support nesting aggregate functions directly (such as AVG(MAX(column))). Use subqueries or Common Table Expressions (CTEs) to perform multi-level aggregations.
This error occurs when you attempt to nest one aggregate function inside another aggregate function in a single query expression. Aggregate functions like SUM(), AVG(), MAX(), MIN(), and COUNT() compute a single consolidated result from multiple rows. PostgreSQL does not allow you to apply an aggregate function to the result of another aggregate function directly because it creates ambiguity in how the aggregation should be computed. While this error message is more commonly associated with Oracle databases, similar restrictions apply in PostgreSQL where they manifest as "aggregate function calls cannot be nested" (error 42803).
Look for patterns where an aggregate function is used as the argument to another aggregate function. For example:
-- This fails:
SELECT AVG(SUM(amount)) FROM orders GROUP BY customer_id;
-- This also fails:
SELECT MAX(COUNT(*)) FROM users GROUP BY department_id;Read the error message to identify which functions are conflicting.
Create an inner query that computes the first aggregation, then wrap it in an outer query that performs the second aggregation:
-- Instead of:
SELECT AVG(SUM(amount)) FROM orders;
-- Use a subquery:
SELECT AVG(total_amount) FROM (
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
) AS customer_totals;The inner query (customer_totals) computes the sum per customer, and the outer query averages those sums.
CTEs provide a cleaner, more readable way to handle multi-level aggregations. They allow you to break the query into logical steps:
-- Using CTE:
WITH customer_totals AS (
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
)
SELECT AVG(total_amount) AS average_customer_spend
FROM customer_totals;This approach is more maintainable and easier to debug than deeply nested subqueries.
If you need more than two levels of aggregation, create multiple CTEs in sequence:
WITH level_one AS (
SELECT category, SUM(price) AS category_total
FROM products
GROUP BY category
),
level_two AS (
SELECT AVG(category_total) AS avg_category_total
FROM level_one
)
SELECT MAX(avg_category_total) AS max_avg
FROM level_two;Each CTE builds on the previous one, making the logic clear and avoiding function nesting.
Test your rewritten query to ensure it produces the correct output:
-- Before (would fail):
SELECT MAX(AVG(salary)) FROM employees GROUP BY department_id;
-- After (works):
WITH dept_avg_salary AS (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
)
SELECT MAX(avg_salary) AS highest_avg_salary
FROM dept_avg_salary;
-- Verify by running both parts separately:
SELECT department_id, AVG(salary) FROM employees GROUP BY department_id;
SELECT MAX(avg_salary) FROM (SELECT AVG(salary) as avg_salary FROM employees GROUP BY department_id);PostgreSQL's restriction on nested aggregates is by design. Aggregate functions operate at the query level and produce single scalar results. Attempting to nest them violates the fundamental semantics of aggregation. Some database systems (like Oracle) allow limited nesting but with strict depth limits. If you find yourself needing multiple aggregation levels frequently, consider whether your data model or query approach could be simplified. Additionally, window functions (OVER clause) can sometimes provide an alternative to nested aggregation for certain use casesโfor example, running totals or ranking within groups. For very complex analytical queries, consider moving aggregation logic to the application layer where you have more flexibility.
ERROR: syntax error at end of input
Syntax error at end of input in PostgreSQL
Bind message supplies N parameters but prepared statement requires M
Bind message supplies N parameters but prepared statement requires M in PostgreSQL
Multidimensional arrays must have sub-arrays with matching dimensions
Multidimensional arrays must have sub-arrays with matching dimensions
ERROR: value too long for type character varying
Value too long for type character varying
insufficient columns in unique constraint for partition key
How to fix "insufficient columns in unique constraint for partition key" in PostgreSQL