In this chapter
We'll uncover the real order SQL runs a query in — FROM, WHERE, SELECT, then ORDER BY — and the exact reason a SELECT alias works in ORDER BY but breaks in WHERE.
The Problem in Real Life
Sarah writes what looks like a clean, obvious query: pull each customer's balance under an alias, filter it down to just the ones who owe something, sort the biggest first. She runs it. It breaks — on the WHERE line, on the exact alias she just typed two lines above it.
Mike watches her stare at the screen. She didn't misspell anything. The alias is sitting right there, in the SELECT line, in plain sight. WHERE insists it doesn't exist.
Debt doesn't exist yet? I just typed it right there.
Sarah
The Order You Write It vs. The Order It Actually Runs
Written order isn't run order
SQL reads top to bottom on the page, but that's not the sequence it actually executes in.
An alias can vanish depending on where it's used
The exact same AS alias works perfectly in ORDER BY and fails outright in WHERE.
"Unknown column" doesn't always mean a typo
A perfectly spelled alias can still fail if it's referenced before SELECT has actually created it.
Aggregates hit the same wall
A computed total can't be filtered by WHERE either — it doesn't exist yet at that point in the sequence.
What Order Does SQL Actually Run In?
Every query so far has been written top to bottom: SELECT, then FROM, then WHERE, then ORDER BY. That's the order Sarah types it in. It is not the order SQL actually runs it.
SQL evaluates a query in a completely different sequence, called its logical execution order. FROM decides which table's rows are even in play. WHERE filters those rows down. SELECT then decides which columns — and which aliases — actually get created. ORDER BY runs last of all, sorting whatever SELECT already produced.
SQL's Real Execution Order
FROM
Pick the starting table
WHERE
Filter rows — no aliases exist yet
SELECT
Create the output columns and aliases
ORDER BY
Sort whatever SELECT already produced
WHERE runs before SELECT — so an alias like AS Debt, created inside SELECT, doesn't exist yet at the point WHERE is evaluated.
SELECT BalanceDue AS DebtFROM CustomersWHERE Debt > 0;
This fails. WHERE runs before SELECT, so the alias Debt doesn't exist yet at the point WHERE is evaluated — the error isn't a typo, it's the execution order.
ORDER BY runs last of all, after SELECT — which is exactly why it's allowed to sort by an alias WHERE could never see.
SELECT BalanceDue AS DebtFROM CustomersORDER BY Debt DESC;
This works. ORDER BY runs after SELECT, so by the time sorting happens, Debt already exists.
FROM decides which table's real column names are in play from the start — WHERE has to reference one of those real names, not an alias SELECT hasn't created yet.
SELECT BalanceDue AS DebtFROM CustomersWHERE BalanceDue > 0ORDER BY Debt DESC;
WHERE has to reference the real column name, BalanceDue — not the alias created later. ORDER BY, running after SELECT, is free to use either one.
The same rule applies to an aggregate's result: TotalCustomers doesn't exist until SELECT runs, so WHERE can't filter on it either — that's exactly what HAVING exists for, coming in Act 3.
SELECT COUNT(*) AS TotalCustomersFROM CustomersWHERE TotalCustomers > 5;
Fails for the same reason — TotalCustomers doesn't exist until SELECT runs, and WHERE has already finished by then. Filtering on an aggregate's result needs a different clause entirely: HAVING, which runs after aggregation — coming in Act 3.
Notice the pattern across all four queries: anything computed inside SELECT — a plain alias or an aggregate's result — doesn't exist yet by the time WHERE runs. ORDER BY, sitting after SELECT in the real execution order, is the only clause among these four allowed to reference it.
This is why the order Sarah types a query in was never the real story. SQL reads top to bottom, but it runs FROM, then WHERE, then SELECT, then ORDER BY — and once GROUP BY and HAVING join that sequence in Act 3, this exact same rule is what explains where they have to sit.
Key Takeaway
SQL is written SELECT-first, but runs FROM, then WHERE, then SELECT, then ORDER BY — which is exactly why a SELECT alias is invisible to WHERE but visible to ORDER BY.
Why This Matters
Every strange "unknown column" error from here forward traces back to this same rule — a query that looks obviously correct can still fail, not from bad syntax, but because something referenced in one clause simply doesn't exist yet at the point that clause runs. Understanding the real execution order turns those errors from mysterious into predictable.
GreenMart's queries finally make sense not just as sentences, but as a real sequence of steps. This closes out everything queries can do against a single table — the checkpoint next is where Mike gets to answer his own real questions, from scratch.
