Informix Error -303
-303 Expression mixes columns with aggregates.
This SELECT statement uses an aggregate function in its WHERE clause. This action is not allowed. The WHERE clause must be applied row by row as a table is scanned, but an aggregate function can only be calculated after all rows have been chosen and grouped. Review the statement with this fact in mind. If you intended to select only certain groups of records, you can put that test in the HAVING clause; it is applied to grouped rows.
The text of this message is somewhat deceptive. You can, in fact, mix column names and aggregate functions in expressions. However, you can do so only in the select list or the HAVING clause (not in the WHERE clause), and the columns must appear in the GROUP BY clause.
Database servers after Version 5.01 do not use this error message.
Oninit® Troubleshooting Guidance
Reasons / Common Causes
-303 is a legacy message worth knowing the history of: it fired when an aggregate function
appeared in a WHERE clause, which isn't logically possible — a WHERE clause is evaluated row
by row as the table is scanned, while an aggregate can only be computed after all qualifying rows
have been selected and grouped. Per the official page, database servers after version 5.01 no
longer use this specific error message (the same underlying mistake now typically surfaces as a
different diagnostic), so encountering -303 itself usually points to a much older server or
older documentation/training material still in circulation.
- An aggregate function (
COUNT,SUM,AVG,MAX,MIN) placed directly in aWHEREclause — the direct, only cause. - Confusing
WHEREandHAVING— reaching forWHEREout of habit when the actual filtering condition depends on an aggregated value, which requiresHAVINGinstead. - Working against a genuinely old server version (5.01 or earlier) where this specific message is what's raised; on later versions the same underlying mistake surfaces differently.
Solutions / Resolution
- Move the aggregate condition into a
HAVINGclause, per the official guidance — aggregates belong in the select list orHAVING, never inWHERE. - Keep any non-aggregate filtering conditions in
WHEREas before; only the aggregate-dependent condition needs to move. - Ensure any plain columns referenced alongside aggregates in the select list or
HAVINGalso appear in theGROUP BYclause, consistent with the general column/aggregate mixing rules (see-294).
Examples
Aggregate mistakenly placed in WHERE
SELECT region, COUNT(*) FROM orders
WHERE COUNT(*) > 10
GROUP BY region;
-- -303 (on older servers): COUNT(*) can't be evaluated
-- row-by-row in WHERE
Fix — move the aggregate condition to HAVING:
SELECT region, COUNT(*) FROM orders
GROUP BY region
HAVING COUNT(*) > 10;
Combining a row-level filter with an aggregate filter
SELECT region, COUNT(*) FROM orders
WHERE order_date >= '2026-01-01'
GROUP BY region
HAVING COUNT(*) > 10;
-- order_date filtering stays in WHERE (row-level);
-- the aggregate condition stays in HAVING
Diagnostic Checks
- Check the
WHEREclause for any aggregate function calls —COUNT,SUM,AVG,MAX,MINdon't belong there. - Check the server version if
-303itself appears — this exact message is retired after version 5.01, so its appearance may point to an old server.
Related Errors / Related Topics
- -294 — "The column column-name must be in the GROUP BY list." The general column/aggregate mixing rule this restriction is part of.
- -300 — "There are too many GROUP BY columns." Another
GROUP BY-adjacent implementation limit in the same query-construction area.
An aggregate condition always belongs in HAVING, never in WHERE — WHERE filters rows before
grouping, HAVING filters groups after aggregation.