SELECT basics
The fundamentals of a SQL query — choosing columns, filtering rows, sorting — and the surprising order they actually run in.
What you'll learn
- How a SELECT statement is built up, clause by clause
- The logical execution order — which is NOT the order you write it in
- Why a SELECT alias can't be used back in WHERE
SELECT is the verb you will reach for more than any other in SQL. It asks a table a question and hands back rows. Throughout this lesson we will put the same small table of users on the desk and ask it things:
| id | name | country | signup_date |
|---|---|---|---|
| 1 | Asha | IN | 2024-01-15 |
| 2 | Bo | CN | 2024-02-03 |
| 3 | Carlos | US | 2024-02-20 |
| 4 | Diya | IN | 2024-03-28 |
| 5 | Erik | US | 2024-01-09 |
The simplest useful query names some columns and a source:
SELECT name, country
FROM users;
| name | country |
|---|---|
| Asha | IN |
| Bo | CN |
| Carlos | US |
| Diya | IN |
| Erik | US |
The order you write is not the order it runs
Here is the thing most tutorials skip. SQL does not run a query top to bottom the way you typed it. It runs the clauses in a fixed logical order, and SELECT — the first word you write — runs almost last:
You write SELECT first, but it runs fifth — which is exactly why a column alias from SELECT can’t be used back in WHERE.
FROM picks the table, WHERE keeps the rows you want, and only then does SELECT choose which columns survive — followed by ORDER BY to sort and LIMIT to trim. Hold this order; it explains a surprising amount.
A quick tour of the clauses
Keep only some rows with WHERE:
SELECT name, signup_date
FROM users
WHERE country = 'IN';
| name | signup_date |
|---|---|
| Asha | 2024-01-15 |
| Diya | 2024-03-28 |
Sort the output with ORDER BY, and keep just the top few with LIMIT — here, the three most recent signups:
SELECT name, signup_date
FROM users
ORDER BY signup_date DESC
LIMIT 3;
| name | signup_date |
|---|---|
| Diya | 2024-03-28 |
| Carlos | 2024-02-20 |
| Bo | 2024-02-03 |
And rename a column on the way out with AS — an alias — which makes bigger, multi-table queries far easier to read:
SELECT name AS user_name,
signup_date AS joined_at
FROM users
LIMIT 2;
| user_name | joined_at |
|---|---|
| Asha | 2024-01-15 |
| Bo | 2024-02-03 |
Notice why the alias rule from the diagram bites: a name you create in SELECT does not exist yet when WHERE runs, because WHERE ran two steps earlier. That single fact resolves the most common “why won’t this query compile?” beginners hit.
Practice
Quick check
Practice this in an interview
All questionsA column alias defined in SELECT can be referenced in ORDER BY but not in WHERE or HAVING, because SELECT runs after those clauses in the logical processing order. To reuse a complex expression in WHERE or HAVING, repeat the expression or wrap the query in a subquery or CTE.
SELECT * fetches every column at query time, so adding or reordering columns in the table silently breaks downstream code, wastes I/O on columns you never use, and prevents the optimizer from doing index-only scans. Always name the columns you need.
SQL processes clauses in this order: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT. This matters because it explains why you cannot use a SELECT alias in a WHERE clause, but you can use it in ORDER BY.
Every core SQL clause — SELECT, WHERE, GROUP BY, HAVING, JOIN, ORDER BY, LIMIT — has a direct pandas equivalent, but SQL executes inside a database engine with optimized query planning and disk-backed storage, while pandas requires all data to fit in RAM. Use SQL for large persistent datasets and pandas for in-memory transformation, feature engineering, and integration with the Python ML ecosystem.