The order SQL actually runs your query in (and why it changes everything)
You write the query in this order:
SELECT customer, SUM(amount) AS total
FROM orders
WHERE state = 'SP'
GROUP BY customer
HAVING SUM(amount) > 1000
ORDER BY total DESC
But the database doesn’t run it in that order. And understanding the real order explains a whole class of errors that look inexplicable.
The real order
SQL runs roughly like this:
FROM— which table the data comes fromWHERE— filters the rows (before grouping)GROUP BY— groups what’s leftHAVING— filters the groups (after grouping)SELECT— picks and computes the columnsORDER BY— sorts the final result
Notice: SELECT, which you write first, is almost the last thing to run.
Why it matters: the alias error
This is the classic error the order explains instantly:
SELECT amount * 1.1 AS amount_with_fee
FROM orders
WHERE amount_with_fee > 100 -- ERROR
The database complains that amount_with_fee doesn’t exist. That makes sense: WHERE runs before SELECT, so at filter time that alias hasn’t been created yet.
The fix is to repeat the expression (or use a subquery/CTE):
SELECT amount * 1.1 AS amount_with_fee
FROM orders
WHERE amount * 1.1 > 100
Why WHERE and HAVING are not the same
Both filter — but at different moments:
WHEREfilters rows, before grouping.HAVINGfilters groups, after grouping.
That’s why you can’t use SUM(amount) > 1000 in WHERE: the group’s sum doesn’t exist yet at that point. It only exists after GROUP BY — HAVING territory.
To remember
The right mental order is: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
When a query throws a “weird” error about a column that doesn’t exist or a filter that won’t work, re-read it in that order. Almost always the problem is using something before the moment it comes into existence.