SQL SELECT Statement
Table of Contents
The SQL SELECT statement reads data from a database. Every read query begins by describing the result you want: stored columns, calculated values, or a combination of both. At its simplest, SELECT name FROM users; returns the name column from every row in users. Real queries can select several columns, rename them with aliases, remove duplicate results, and combine SELECT with clauses that filter, group, sort, or limit rows. This guide starts with the basic syntax, then explains wildcards, expressions, DISTINCT, clause order, and the mistakes that most often make a query fail or return a surprising result.
This article is based on the "Introduction" and "Basic Queries" chapters of Learn SQL. If you want to run each query as you read, take the full course.
SQL SELECT Statement Syntax
SELECT retrieves rows and computes the values returned for each one. The output is a result set, or the table of rows produced by the query. SELECT doesn't change stored data.
Databases are made up of tables which are made up of columns (AKA "fields"). It's just like an Excel spreadsheet. Say we have a users table with these columns:
id(integer)name(string)age(integer)balance(float)is_admin(boolean: true/false)
There can be many records (rows) in this table, each representing a single user. For example, here are three user rows:
| id | name | age | balance | is_admin |
|---|---|---|---|---|
| 1 | John Smith | 28 | 450 | 1 |
| 2 | Darren Walker | 27 | 200 | 1 |
| 3 | Jane Morris | 33 | 496.24 | 0 |
Here's the basic syntax:
SELECT column_name
FROM table_name;
Returns only the name column from the users table:
SELECT name FROM users;
SELECT name controls the output column. FROM users identifies the source table. All SQL statements must end with a semicolon ;. PostgreSQL documents the full SELECT syntax, while SQLite's SELECT documentation describes its own dialect and execution model.
SQL describes the result to return instead of requiring you to specify each retrieval step. Read what SQL is for the broader database context.
Selecting One or More Columns
As you probably guessed, if you can select a single column by name, you can probably also select multiple columns by name. Here's the syntax:
select column_one, column_two, column_three from table_name;
For example, if I had a table of monster records for a game, I might write:
select health, damage, defense from monsters;
The result follows the order of the expressions after SELECT. This query returns health first, damage second, and defense third, regardless of their order in the table definition.
Select only the data you need. A narrow result is easier to understand, gives application code a stable shape, and avoids moving unused data between the database and your backend. Even if an object-relational mapper (ORM) writes some queries for you, backend developers still need SQL to inspect and fix them.
The SELECT * Wildcard
The asterisk is a wildcard, a symbol that stands for every column available from the query's source. To get all the columns instead of naming each one, we simply swap out the column names for a *.
Returns all columns from the users table:
SELECT * FROM users;
SELECT * is useful while exploring a table or typing a quick one-off query. Don't make it the default in application code. If someone adds a large or sensitive column later, the query starts returning it without any change to the query itself. Column order and result shape can also change with the schema.
Name the required columns explicitly when code depends on the result:
SELECT id, name, balance
FROM users;
The wildcard doesn't have to be everything after SELECT. You can return every stored column and append a calculated one:
SELECT users.*, balance * 100 AS balance_cents
FROM users;
Qualifying the wildcard as users.* becomes especially useful when queries combine tables with SQL joins.
SQL Column Aliases
Sometimes we need to structure the data we return from our queries in a specific way. An AS clause allows us to "alias" a piece of data in our query. The alias exists only for the duration of the query — it changes the result's label, not the table's schema or stored data.
The following queries return the same data:
SELECT employee_id AS id, employee_name AS name
FROM employees;
SELECT employee_id, employee_name
FROM employees;
The difference is that the results from the aliased query would have column names id and name instead of employee_id and employee_name.
Aliases are most important for expressions, which otherwise get database-generated labels:
SELECT price * quantity AS line_total
FROM order_items;
Use short, descriptive aliases. Avoid spaces and punctuation unless you have a strong reason to create a quoted identifier, a name wrapped in quotes. SQL systems disagree enough about quoted identifiers and case handling that simple snake_case aliases are the least surprising choice.
Calculated Columns With SELECT
SQL is a programming language, and like nearly all programming languages, it supports functions. We can use functions and aliases to calculate new columns in a query. This is similar to how you might use formulas in Excel. A calculated column is a new column that doesn't exist in the original table but is created on the fly when you run a query — nothing is written back to the table.
SELECT product_name, price, quantity,
price * quantity AS inventory_value
FROM products;
In SQLite, the IIF function works like a ternary expression. For example:
IIF(carA > carB, 'Car A is bigger', 'Car B is bigger')
If carA is greater than carB, this statement evaluates to the string 'Car A is bigger'. Otherwise, it evaluates to 'Car B is bigger'.
Here's how we can use IIF() and a directive alias to add a new calculated column to our result set:
SELECT quantity,
IIF(quantity < 10, 'Order more', 'In Stock') AS directive
FROM products;
Other SQL dialects may not have IIF. CASE does the same job and works across SQL databases:
SELECT product_name, quantity,
CASE
WHEN quantity < 10 THEN 'Order more'
ELSE 'In stock'
END AS directive
FROM products;
CASE checks each WHEN condition in order and returns the result from the first match. ELSE supplies the fallback. The expression ends with END, and AS directive names the calculated column. Prefer CASE when a query needs to run across database systems.
Functions can also appear after SELECT. Aggregate functions such as COUNT, SUM, and AVG summarize several rows instead of calculating one independent value per row. The SQL aggregate functions reference covers them.
Removing Duplicates With SELECT DISTINCT
Sometimes we want to retrieve records from a table without getting back any duplicates. For example, we may want to know all the different companies our employees have worked at previously, but we don't want to see the same company multiple times in the report.
SQL offers us the DISTINCT keyword that removes duplicate records from the resulting query. It doesn't delete or update anything in the source table.
SELECT DISTINCT previous_company
FROM employees;
This only returns one row for each unique previous_company value.
The same idea answers questions like "which countries do our users come from?":
SELECT DISTINCT country_code
FROM users;
If 500 users come from exactly three countries, this query returns those three country codes, plus one NULL row if any user has no country code. Multiple NULL results are treated as duplicates for this purpose and collapse to one NULL row.
With multiple selected columns, DISTINCT applies to the complete combination:
SELECT DISTINCT country_code, age
FROM users;
Two output rows are duplicates only when both their country_code and age values match. DISTINCT does not make each selected column independently unique.
Don't use DISTINCT to hide a broken join or unwanted duplicate records. If stored rows must be unique, enforce that rule with SQL constraints. If a query unexpectedly multiplies rows, fix its join conditions.
SELECT Clause Order
A practical written order for common SELECT clauses is:
SELECT [DISTINCT] expressions
FROM tables
WHERE row_conditions
GROUP BY grouping_expressions
HAVING group_conditions
ORDER BY sort_expressions
LIMIT row_count;
The brackets mark DISTINCT as optional; don't type them. Most clauses are optional, but the ones you use must follow the database's required order. LIMIT works in PostgreSQL, SQLite, and MySQL. SQL Server and standard SQL limit rows differently.
Each clause has one job:
| Clause | Purpose |
|---|---|
SELECT |
Chooses output columns and expressions |
FROM |
Identifies source tables |
WHERE |
Filters source rows |
GROUP BY |
Forms groups for aggregate calculations |
HAVING |
Filters groups |
ORDER BY |
Sorts the final result |
LIMIT |
Caps the number of returned rows |
Written order isn't the same as processing order. The database builds and filters the source rows before evaluating the final select list. That's why a column alias defined in SELECT usually can't be referenced by WHERE in the same query.
Use the SQL ORDER BY and LIMIT guide for sorting and pagination. The SQL WHERE clause and SQL LIKE operator references cover filtering and text matching.
Common SELECT Statement Mistakes
Missing commas
Every item after SELECT needs a comma before the next one:
SELECT name, age, balance
FROM users;
Without the commas, the database may report a syntax error or interpret a token as an alias.
Putting clauses in the wrong order
WHERE belongs after FROM, while ORDER BY belongs after filtering and grouping:
SELECT name, balance
FROM users
WHERE balance > 0
ORDER BY balance DESC;
Learn the clause order instead of shuffling keywords until the parser accepts the query.
Expecting a guaranteed row order
A query without ORDER BY has no guaranteed row order. An index change, database upgrade, or new execution plan can rearrange the same result. Add ORDER BY whenever order matters.
Frequently Asked Questions
What does the SQL SELECT statement do?
SELECT reads data and returns a result set made from columns, expressions, and rows. It does not change the stored data.
How do I select multiple columns in SQL?
List the column names after SELECT and separate them with commas, such as SELECT name, age, balance FROM users.
What is the difference between SELECT and SELECT DISTINCT?
SELECT returns every matching result row. SELECT DISTINCT removes duplicate result rows based on the complete set of selected values.
Should I use SELECT * in SQL?
Use SELECT * for quick exploration. In application code, explicitly name the required columns so schema changes do not silently change the result.
Can SELECT calculate a column that is not stored in the table?
Yes. The select list can contain arithmetic, functions, and CASE expressions. Give calculated columns a clear alias with AS.
