10.4. SELECT
Table of Contents
Basic idea of `SELECT`
The SELECT statement reads data from a table and returns it as a result set.
Very simple form:
SELECT column1, column2
FROM table_name;Example, imagine a table:
users:
| id | username | age | |
|---|---|---|---|
| 1 | alice | alice@example.com | 25 |
| 2 | bob | bob@example.com | 31 |
| 3 | carol | carol@example.com | 29 |
Query:
SELECT id, username
FROM users;Result:
| id | username |
|---|---|
| 1 | alice |
| 2 | bob |
| 3 | carol |
Core rule:
SELECT defines what columns you want, FROM defines which table(s) you read from.
You can select all columns with *:
SELECT *
FROM users;
This returns every column in users. This is handy while learning, but in real applications you usually avoid SELECT * and specify only the columns you need.
Column lists and aliases
Selecting specific columns
You can list any number of columns:
SELECT username, email, age
FROM users;
Order matters: the result columns appear in the same order as in the SELECT list, not necessarily in the table definition order.
You can even repeat a column:
SELECT username, age, age
FROM users;
Result has three columns, the last two are both age.
This is rarely useful in real systems, but it shows that the SELECT list is independent from the table structure.
Column aliases with `AS`
Aliases rename columns in the result, not in the table. They are useful when:
- you compute values
- you have long or unclear column names
- you join tables (later chapter) and want clear names
Syntax:
SELECT column_name AS alias_name
FROM table_name;Examples:
SELECT
username AS user_name,
email AS contact_email
FROM users;Result:
| user_name | contact_email |
|---|---|
| alice | alice@example.com |
| bob | bob@example.com |
| carol | carol@example.com |
AS is optional, you can write:
SELECT
username user_name,
email contact_email
FROM users;
Both forms are equivalent. Using AS is usually clearer and easier to read.
Aliases can also be used for computed columns:
SELECT
username,
age + 1 AS age_next_year
FROM users;Result:
| username | age_next_year |
|---|---|
| alice | 26 |
| bob | 32 |
| carol | 30 |
Important: Aliases change only the column names in the query output, they do not change the actual column names in the database.
Selecting all columns with `*`
* means “all columns” from the tables in the FROM clause.
SELECT *
FROM users;
This returns all columns of users.
You can combine * with extra computed columns:
SELECT
*,
age + 10 AS age_in_10_years
FROM users;Result:
| id | username | age | age_in_10_years | |
|---|---|---|---|---|
| 1 | alice | alice@example.com | 25 | 35 |
| 2 | bob | bob@example.com | 31 | 41 |
| 3 | carol | carol@example.com | 29 | 39 |
Why `SELECT *` can be a problem in backends
For learning, SELECT * is fine. In real applications, it can be harmful:
- It may fetch more data than needed, which is slower.
- If someone adds a new big column (for example a large JSON field or image data) your app might suddenly start moving a lot more data.
- It can break code that depends on column order or count.
Better to explicitly list columns:
SELECT id, username, email, age
FROM users;Constants and simple expressions
You are not limited to table columns in the SELECT list. You can add:
- constants
- arithmetic expressions
- string operations
- functions (will be covered later but you will see a bit here)
Adding constant values
SELECT
username,
'ACTIVE' AS status
FROM users;Result:
| username | status |
|---|---|
| alice | ACTIVE |
| bob | ACTIVE |
| carol | ACTIVE |
Every row gets the same constant value in the status column.
You can also use numeric constants:
SELECT
username,
age,
18 AS legal_age_limit
FROM users;Result:
| username | age | legal_age_limit |
|---|---|---|
| alice | 25 | 18 |
| bob | 31 | 18 |
| carol | 29 | 18 |
Arithmetic expressions
Basic arithmetic works like in most programming languages:
| Operator | Meaning |
|---|---|
+ | addition |
- | subtraction |
* | multiplication |
/ | division |
Examples:
SELECT
username,
age,
age + 5 AS age_in_5_years,
age * 12 AS age_in_months,
age / 10.0 AS age_div_10
FROM users;Result:
| username | age | age_in_5_years | age_in_months | age_div_10 |
|---|---|---|---|---|
| alice | 25 | 30 | 300 | 2.5 |
| bob | 31 | 36 | 372 | 3.1 |
| carol | 29 | 34 | 348 | 2.9 |
You can mix column names and constants in expressions.
Tip: Always give expressions an alias. Otherwise the column name in the result is the expression text itself, which is hard to use and read.
Removing duplicate rows with `DISTINCT`
By default, SELECT returns one row for each matching row in the table, even if several rows have the same values in the selected columns.
DISTINCT removes duplicate rows from the result.
Syntax:
SELECT DISTINCT column1, column2, ...
FROM table_name;Imagine a simple table:
orders:
| id | user_id | status |
|---|---|---|
| 1 | 1 | pending |
| 2 | 2 | shipped |
| 3 | 1 | shipped |
| 4 | 3 | pending |
| 5 | 2 | shipped |
Without DISTINCT:
SELECT status
FROM orders;Result:
| status |
|---|
| pending |
| shipped |
| shipped |
| pending |
| shipped |
With DISTINCT:
SELECT DISTINCT status
FROM orders;Result:
| status |
|---|
| pending |
| shipped |
If you select more than one column, DISTINCT works on the combination of those columns.
Example:
SELECT DISTINCT user_id, status
FROM orders;Result:
| user_id | status |
|---|---|
| 1 | pending |
| 2 | shipped |
| 1 | shipped |
| 3 | pending |
Even though status = 'pending' appears multiple times, the pair (3, 'pending') is distinct from (1, 'pending').
Rule:
DISTINCT keeps only unique combinations of all selected columns together, not each column separately.
Basic filtering with `WHERE` (preview)
Full details of WHERE belong in the WHERE chapter, but it is very hard to talk about SELECT without touching it at all. You will see only simple examples here.
WHERE filters rows before they are returned. Only rows that satisfy the condition are included.
General pattern:
SELECT column_list
FROM table_name
WHERE condition;Examples:
-- Users older than 25
SELECT id, username, age
FROM users
WHERE age > 25;Result (with our sample data):
| id | username | age |
|---|---|---|
| 2 | bob | 31 |
| 3 | carol | 29 |
Another example:
-- Orders that are shipped
SELECT id, user_id, status
FROM orders
WHERE status = 'shipped';Result:
| id | user_id | status |
|---|---|---|
| 2 | 2 | shipped |
| 3 | 1 | shipped |
| 5 | 2 | shipped |
Later, in the WHERE chapter, you will learn about more complex conditions with AND, OR, IN, LIKE, and working with NULL.
Ordering results with `ORDER BY` (preview)
Again, full details belong in the ORDER BY chapter, but you need a quick idea here.
ORDER BY sorts the result rows.
General pattern:
SELECT column_list
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;ASCmeans ascending order, small to large, A to Z. It is the default.DESCmeans descending order, large to small, Z to A.
Example:
SELECT id, username, age
FROM users
ORDER BY age;Result:
| id | username | age |
|---|---|---|
| 1 | alice | 25 |
| 3 | carol | 29 |
| 2 | bob | 31 |
Now reverse the order:
SELECT id, username, age
FROM users
ORDER BY age DESC;Result:
| id | username | age |
|---|---|---|
| 2 | bob | 31 |
| 3 | carol | 29 |
| 1 | alice | 25 |
You can also sort by multiple columns:
SELECT id, username, age
FROM users
ORDER BY age DESC, username ASC;This sorts first by age descending, and for equal ages by username ascending.
Limiting the number of rows (`LIMIT` / `OFFSET`) (preview)
Limiting belongs more naturally with pagination, but it is very commonly used with simple SELECT queries.
In many database systems, you can restrict the number of rows using LIMIT.
General pattern:
SELECT column_list
FROM table_name
ORDER BY some_column
LIMIT n;
n is the maximum number of rows you want.
Example:
-- Only the first 2 users when ordered by id
SELECT id, username
FROM users
ORDER BY id
LIMIT 2;Result:
| id | username |
|---|---|
| 1 | alice |
| 2 | bob |
You can skip some rows using OFFSET:
SELECT id, username
FROM users
ORDER BY id
LIMIT 2 OFFSET 1;This means: skip the first row, then return 2 rows.
Result:
| id | username |
|---|---|
| 2 | bob |
| 3 | carol |
You will revisit these concepts in more depth when learning about pagination.
Practical examples for backend developers
To connect SELECT with typical backend tasks, imagine more realistic tables.
Example 1: Basic user listing for an admin API
Table users (extended):
| id | username | age | created_at | |
|---|---|---|---|---|
| 1 | alice | alice@example.com | 25 | 2024-01-01 10:00:00 |
| 2 | bob | bob@example.com | 31 | 2024-02-15 09:30:00 |
| 3 | carol | carol@example.com | 29 | 2024-03-05 11:45:00 |
Query for an admin list:
SELECT
id,
username,
email,
created_at
FROM users
ORDER BY created_at DESC
LIMIT 20;
This gives the 20 most recently created users for an admin endpoint like GET /admin/users.
Example 2: Status counts with constants
Imagine your backend needs to show the current status label together with each order.
orders:
| id | user_id | status | total_amount |
|---|---|---|---|
| 1 | 1 | pending | 49.99 |
| 2 | 2 | shipped | 19.99 |
| 3 | 1 | shipped | 5.00 |
You might want a label that you compute in the app, but during development you can test it in SQL:
SELECT
id,
status,
total_amount,
'USD' AS currency
FROM orders;Result:
| id | status | total_amount | currency |
|---|---|---|---|
| 1 | pending | 49.99 | USD |
| 2 | shipped | 19.99 | USD |
| 3 | shipped | 5.00 | USD |
Example 3: Selecting distinct values for filters
For building filter dropdowns in a UI, you can query unique values.
SELECT DISTINCT status
FROM orders
ORDER BY status;
Your backend endpoint could use this result to populate a filter list like ["pending", "shipped", "cancelled"].
Summary
SELECTdefines what data to return,FROMdefines from where.- You can:
- select specific columns:
SELECT id, username FROM users; - select all columns:
SELECT * FROM users; - give columns or expressions aliases with
ASfor clearer results. - include constants and arithmetic expressions in the
SELECTlist. - remove duplicate rows with
SELECT DISTINCT .... - preview basic filtering with
WHERE, sorting withORDER BY, and limiting rows withLIMIT/OFFSET.
In later chapters like WHERE, ORDER BY, GROUP BY, and JOINs, you will combine these building blocks into more powerful queries. For now, practice writing simple SELECT queries on a sample database, changing the column list, adding aliases, constants, and small expressions.
Views: 7
KAHIBARO