Основы и SELECT
SQL для новичков: основы и SELECT¶
SQL (Structured Query Language) — язык, с помощью которого ты просишь базу данных показать, добавить, изменить или удалить данные. SQL — декларативный: ты описываешь что хочешь получить, а не как это сделать пошагово.
В этой статье ты научишься извлекать данные из таблиц, фильтровать строки, сортировать результаты и работать с NULL-значениями.
Подготовка данных¶
Для работы с примерами понадобятся четыре таблицы.
DDL и INSERT — разверни и скопируй в PostgreSQL
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP NOT NULL
);
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(80) NOT NULL,
price DECIMAL(10,2) NOT NULL
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT NOT NULL,
status VARCHAR(20) NOT NULL,
created_at TIMESTAMP NOT NULL
);
CREATE TABLE order_items (
order_id INT NOT NULL,
product_id INT NOT NULL,
qty INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
PRIMARY KEY (order_id, product_id)
);
INSERT INTO users (id, name, email, created_at) VALUES
(1, 'Анна', 'anna@example.com', '2026-01-10 10:00:00'),
(2, 'Борис', 'boris@example.com', '2026-01-11 12:30:00'),
(3, 'Хлоя', 'chloe@example.com', '2026-01-12 09:15:00');
INSERT INTO products (id, name, price) VALUES
(1, 'Клавиатура', 49.90),
(2, 'Мышь', 19.90),
(3, 'Монитор', 199.00),
(4, 'Кабель USB-C', 9.90);
INSERT INTO orders (id, user_id, status, created_at) VALUES
(1001, 1, 'paid', '2026-01-20 14:00:00'),
(1002, 1, 'new', '2026-01-22 18:10:00'),
(1003, 2, 'canceled', '2026-01-23 09:05:00');
INSERT INTO order_items (order_id, product_id, qty, price) VALUES
(1001, 1, 1, 49.90),
(1001, 2, 2, 19.90),
(1002, 3, 1, 199.00),
(1003, 4, 3, 9.90),
(1003, 2, 1, 19.90);
Таблица = колонки (поля) + строки (записи).
SELECT: выбираем данные из таблицы¶
Самый базовый запрос состоит из двух ключевых слов: SELECT (что взять) и FROM (откуда).
| id | name | price |
|---|---|---|
| 1 | Клавиатура | 49.90 |
| 2 | Мышь | 19.90 |
| 3 | Монитор | 199.00 |
| 4 | Кабель USB-C | 9.90 |
Не используй SELECT * в продакшене
Всегда указывай имена колонок явно: SELECT name, price FROM products. Это экономит ресурсы, ускоряет передачу данных и защищает код от поломки при добавлении новых колонок в таблицу.
Явное перечисление полей:
| id | name | |
|---|---|---|
| 1 | Анна | anna@example.com |
| 2 | Борис | boris@example.com |
| 3 | Хлоя | chloe@example.com |
Псевдонимы (alias)¶
С помощью AS ты можешь переименовать колонку в выдаче:
AS можно опускать
FROM users u и FROM users AS u — одно и то же. Короткие псевдонимы экономят место в сложных запросах с JOIN.
WHERE: фильтруем строки¶
Операторы сравнения¶
| name | price |
|---|---|
| Клавиатура | 49.90 |
| Монитор | 199.00 |
Доступны: =, <> (не равно), >, <, >=, <=.
AND / OR / NOT¶
| name | price |
|---|---|
| Клавиатура | 49.90 |
| Мышь | 19.90 |
То же самое через BETWEEN:
BETWEEN включает границы
BETWEEN 10 AND 50 эквивалентно >= 10 AND <= 50.
IN: значение из списка¶
| id | name |
|---|---|
| 1 | Клавиатура |
| 3 | Монитор |
| 4 | Кабель USB-C |
ORDER BY: сортировка¶
По умолчанию база возвращает строки в произвольном порядке. ORDER BY гарантирует нужный:
| name | price |
|---|---|
| Монитор | 199.00 |
| Клавиатура | 49.90 |
| Мышь | 19.90 |
| Кабель USB-C | 9.90 |
ASC— по возрастанию (по умолчанию)DESC— по убыванию
Сортировка по нескольким полям:
| id | user_id | status | created_at |
|---|---|---|---|
| 1003 | 2 | canceled | 2026-01-23 09:05:00 |
| 1002 | 1 | new | 2026-01-22 18:10:00 |
| 1001 | 1 | paid | 2026-01-20 14:00:00 |
LIMIT и OFFSET: пагинация¶
Если данных много, ограничь выдачу:
| name | price |
|---|---|
| Монитор | 199.00 |
| Клавиатура | 49.90 |
Пагинация — пропустить первые N строк:
| name | price |
|---|---|
| Монитор | 199.00 |
| Кабель USB-C | 9.90 |
DISTINCT: убираем дубликаты¶
Когда нужен список уникальных значений:
| status |
|---|
| paid |
| new |
| canceled |
DISTINCT и производительность
DISTINCT сортирует или хэширует все строки — на больших таблицах это дорого. Если уникальность гарантирована (например, первичный ключ), DISTINCT не нужен.
NULL: нет значения¶
NULL — это не ноль и не пустая строка. Это отсутствие значения. Его нельзя сравнивать через =:
-- Неправильно: всегда вернёт 0 строк
SELECT * FROM users WHERE email = NULL;
-- Правильно
SELECT * FROM users WHERE email IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;
Три значения логики
Любое сравнение с NULL даёт не TRUE и не FALSE, а UNKNOWN. Поэтому WHERE email = NULL не работает — условие никогда не будет истинным.
Порядок выполнения SELECT¶
Ты пишешь запрос сверху вниз, но база выполняет его в другом порядке:
| Шаг | Клауза | Что делает |
|---|---|---|
| 1 | FROM / JOIN |
Определяет источник данных |
| 2 | WHERE |
Фильтрует строки |
| 3 | GROUP BY |
Группирует |
| 4 | HAVING |
Фильтрует группы |
| 5 | SELECT |
Формирует колонки |
| 6 | DISTINCT |
Убирает дубликаты |
| 7 | ORDER BY |
Сортирует |
| 8 | LIMIT |
Ограничивает выдачу |
Почему это важно
Псевдонимы из SELECT нельзя использовать в WHERE — потому что WHERE выполняется раньше. Зато в ORDER BY можно — он выполняется после SELECT.
Что запомнить¶
SELECT+FROM— базовая конструкция для чтения данныхWHEREфильтрует строки до агрегацииORDER BYгарантирует порядок, без него порядок случайныйLIMIT/OFFSET— пагинация результатовDISTINCTубирает дубликаты, но стоит дорогоNULLпроверяется черезIS NULL/IS NOT NULL, не через=- Порядок выполнения запроса ≠ порядок записи
Теперь ты умеешь выбирать и фильтровать данные из одной таблицы. Следующий шаг — объединять данные из нескольких таблиц через JOIN.
Попробуй сам¶
Интерактивная песочница с настоящим PostgreSQL прямо в браузере. База etl_kitchen_db уже загружена — пиши запросы и жми Выполнить (или ++Ctrl+Enter++).
Проверь себя¶
Источники¶
- PostgreSQL: SELECT Lists — официальная документация по выбору колонок и псевдонимам
- PostgreSQL: Sorting Rows — ORDER BY, NULLS FIRST/LAST
- PostgreSQL: LIMIT and OFFSET — пагинация результатов