Blog›SQL Order of Execution: How Queries Actually Run
SQL SkillsGetting Started
The Order SQL Actually Runs Your Query
You read a query from SELECT down. The database runs it in a completely different order, starting with FROM and reaching SELECT almost last. Press play and watch a real query run, stage by stage.
CR
Conor Robertson
July 9, 2026 · 8 min read
Frequently asked questions
The questions that come up most once people realise their query runs in a different order than they wrote it.
Ready to practice on real data?
QueryCase teaches SQL through mystery cases on real datasets. Music, sports, film, and more. Your first cases are completely free.
You read it SELECT first. The engine runs it FROM first, and reaches SELECT only at step 5.
after FROM7rows
namesquadxp
FoxAlpha3,950
RavenAlpha3,200
ValaAlpha1,500
OwliverBravo2,100
SterlingBravo1,450
QuillBravo600
KestrelGamma1,800
✓ rows✗ COUNT(*)✗ cases_closed
FROM
The database starts here, not at SELECT. It loads every row from the source table before anything else can happen.
Almost everyone writes a SQL query the same way: SELECT first, then FROM, then the filters. So it is natural to assume that is the order it runs in. It is not. The database ignores the order you typed and follows its own, starting with FROM and reaching SELECT near the end.
This is not trivia. The order of execution is the single mental model that explains a whole category of confusing errors: why an alias works in ORDER BY but not WHERE, why HAVING exists at all, and why you cannot filter on a window function. Press Run above and watch a real query move through its seven stages. Notice the numbers down the left of the query: that is the order the clauses actually fire, and they are not 1 to 7 top to bottom.
Once you can see those stages, the rules stop being things to memorise and start being obvious.
You write it in one order, SQL runs it in another
Here is the order the database actually follows, as a staircase from first step to last. You typed SELECT at the very top of your query, yet it does not run until step five, after the rows have been filtered and grouped. Only sorting and trimming happen after it.
The reason it works this way is logical, not arbitrary. You cannot filter groups before you have made the groups. You cannot compute a SELECT column that averages a group before the group exists. So the database has to build the row set (FROM), narrow it (WHERE), gather it into groups (GROUP BY), filter those groups (HAVING), and only then work out what each output row looks like (SELECT). Sorting and trimming come last because they only make sense once the final rows exist.
Logical order, not physical order
One honest caveat. This is the logical order of execution: the sequence that defines what your query means. The engine's optimiser is free to shuffle the physical work for speed, like using an index to filter earlier, as long as the result is identical to what this order would produce. So you reason about correctness with the order below, and let the database worry about performance. For every rule in this post, the logical order is the one that matters.
Why this explains half your SQL errors
Now the payoff. Nearly every "why won't this run?" moment with filtering comes down to one rule: a clause can only see what earlier steps have already produced. Pick a query below and see exactly which step trips it up.
SELECT xp * 2 AS double_xp
FROM detectives
WHEREdouble_xp > 5000
✗ ERRORon double_xp
WHERE runs at step 2, but the alias double_xp is not created until SELECT at step 5. It does not exist yet when WHERE looks for it.
FixRepeat the expression: WHERE xp * 2 > 5000. Or compute it in a CTE and filter the outer query.
Every one of these is the same story told with different clauses. WHERE runs early, so it cannot see aliases, aggregates or window functions, because none of them exist yet. HAVING and ORDER BY run late, so they can. Learn the order once and you stop guessing which filter goes where.
The full order, and what each step can see
Here is the whole sequence in one table. The last column is the one to internalise, because "what a step can see" is what decides whether your query runs or errors.
That is the entire model. FROM builds, WHERE filters rows, GROUP BY gathers, HAVING filters groups, SELECT computes, ORDER BY sorts, LIMIT trims. Seven steps, always the same order, in every major database.
The fastest way to lock this in is to use it. Next time a query throws an "unknown column" or "cannot use aggregate here" error, do not guess. Find the clause, ask which step it runs at, and ask whether the thing it references exists yet. Nine times out of ten the answer is right there. Once you have it, JOIN, CASE and window functions all stop being separate rules to remember and become one pipeline you can see.
SQL Order of Execution: How Queries Actually Run | QueryCase