Skip to content
Reference / SQL SELECT Statement Syntax
Reference

SQL SELECT Statement Syntax

The shape of a query, the order you write its clauses, and their logical processing order.

A SELECT query reads rows from one or more tables and returns a result set. You write the clauses in a fixed order, even though the database evaluates them in a different order.

Full shape
select   column_a, column_b, count(*)
from     some_table
where    column_a > 0          -- filter rows
group by column_a, column_b    -- collapse into groups
having   count(*) > 5          -- filter groups
order by count(*) desc         -- sort the result
limit    10                    -- keep the first N rows

Clauses

Clause Purpose
SELECT Which columns or expressions to return.
FROM Which table(s) to read, including joins.
WHERE Keep only rows that match a condition (before grouping).
GROUP BY Collapse rows into one row per group.
HAVING Keep only groups that match a condition (after grouping).
ORDER BY Sort the final result.
LIMIT Return at most N rows.

Logical processing order

This logical order is a useful model for understanding SQL semantics; it is not a claim about the physical order an optimizer uses to execute the query. It also explains why many engines do not let you use a SELECT alias in WHERE, while allowing it in ORDER BY.

  1. FROM / joins
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT (aliases are created here)
  6. ORDER BY
  7. LIMIT

SQL order of execution walks one query through every step, with the row count each step hands to the next.

Columns, aliases, and DISTINCT

Example
select distinct
       category_id,
       product_name as name,
       price * 0.9   as sale_price
from   products
order by sale_price desc

* returns every column. That is handy while exploring, but name the columns you need in real queries. DISTINCT removes duplicate rows from the result. AS renames a column in the output.

Dialect note

DuckDB lets you reference a SELECT alias in WHERE and GROUP BY as a convenience. PostgreSQL and MySQL accept the alias in GROUP BY but not in WHERE; SQL Server accepts it in neither. Repeat the full expression in WHERE to stay portable.