Abstract¶
Решил попробовать создать персональный CheatSeet. Пока не нравится. Либо пойму как переделать, либо удалю.
Тем более что существут интерактивные справочники:
MySQL Reference Manual официальный от Oracle
Справочник по функциям от SQL Academy
MySQL Documents от datacamp
SQL Tutorials от W3 schools
MySQL Tutorial от MySQL Tutorial
PostgreSQL Документация от PostgresPro
SQL Style Guide¶
Ключевые правила хорошего тона (своего рода “SQL-PEP8”):
1. Ключевые слова – ЗАГЛАВНЫМИ БУКВАМИ:
SELECT,FROM,WHERE,AND,OR,ORDER BY,TIMESTAMP.
2. Имена таблиц и колонок – маленькими буквами (snake_case):
users,date_joined,first_name.
3. Отступы (Indentations):
Стандартный отступ – 4 пробела (как в Python) или 2 пробела. \
4. Перенос условий в WHERE:
Каждое условие с
ANDилиORпишется с новой строки.Служебное слово
AND/ORобычно выравнивают:
-- Стиль с отступом в 2 пробела:
WHERE email ILIKE '%@bk.ru'
AND EXTRACT(year FROM date_joined) = 2022
-- Либо стиль с отступом в 4 пробела:
WHERE email ILIKE '%@bk.ru'
AND EXTRACT(year FROM date_joined) = 20225. Запятые в SELECT:
Каждое поле – строго на отдельной строке. Запятая ставится в конце строки (trailing commas):
SELECT
id,
username,
email,
date_joined
FROM users6. По поводу функций в мире SQL есть два лагеря:
Школа 1 (Классическая / ANSI SQL / GitLab / большинство учебников): \
Правило: Всё, что встроено в язык и систему (ключевые слова + типы данных + встроенные функции), пишется ЗАГЛАВНЫМИ БУКВАМИ, а всё, что создал пользователь (таблицы, колонки, алиасы), – строчными.
Пример:
SELECT
user_id,
ROUND(score, 2),
COALESCE(email, 'нет'),
DATE_TRUNC('month', date_joined)
FROM users;Плюс: Глаз мгновенно видит логику: белые/синие заглавные буквы – это операторы и функции, а маленькие строчные – это данные из таблицы.
Школа 2 (PostgreSQL Native / SQLFluff default / DBeaver):
Правило: Ключевые слова каркаса (
SELECT,FROM,WHERE,JOIN) – ЗАГЛАВНЫМИ, а вызовы функций (count(),round(),to_char()) – строчными (как функции в Python: print(), len()).Почему именно в PostgreSQL и DBeaver так любят строчные? В системных таблицах каталога PostgreSQL (pg_proc) все имена встроенных функций физически записаны маленькими буквами:
date_trunc,to_char,lower. DBeaver берёт подсказки напрямую из системного каталога Postgres, поэтому и подставляет их в строчном виде.
Оба варианта признаются профессиональными. Главное – быть последовательным внутри своего проекта:
Если пишешь
ROUND(),COALESCE(),TO_CHAR()заглавными – пиши их все заглавными.Если решил писать строчными
round(),coalesce(),to_char()– пусть они все будут строчными.
SQLFluff, dbt Style Guide и GitLab SQL Style Guide
Все три сущности – это общепринятые в индустрии стандарты и инструменты, решающие одну задачу: сделать SQL-код в командах аккуратным, предсказуемым и легко читаемым без бесконечных споров на код-ревью.
SQLFluff (Автоматический контролёр качества кода)
SQLFluff – открытый диалектно-независимый линтер и автоформатер для SQL.
Как работает: Анализирует код на соответствие правилам выбранного стайлгайда (регистры, отступы, порядок предложений, пробелы вокруг операторов). Если в коде нарушен стандарт, линтер выведет список ошибок с точными строками и номерами правил.
Команда
sqlfluff fix: Автоматически форматирует файл и исправляет большинство проблем с отступами, регистрами ключевых слов и переносами за доли секунды.Связь с практикой: SQLFluff выполняет ту же роль для SQL, что
flake8,blackилиruffдля Python.
dbt Style Guide (Стандарт современной аналитики и DWH)
Руководство по стилю от создателей dbt Labs – де-факто мировой ориентир для аналитиков данных и дата-инженеров, работающих с облачными хранилищами (Snowflake, BigQuery, ClickHouse, Redshift).
Строчные ключевые слова: В отличие от классической школы ANSI SQL, dbt рекомендует писать все ключевые слова (
select,from,where,group by) строчными буквами (lowercase).Приоритет CTE: Запрет на глубоко вложенные подзапросы в блоках
FROMиJOIN. Любая промежуточная логика оформляется в виде именованных выраженийWITHв самом начале запроса.Явные псевдонимы: Обязательное использование ключевого слова
asпри назначении алиасов колонкам (count(*) as total_records).Запятые строго в конце строки: Стандарт dbt прямо предписывает использовать замыкающие запятые (trailing commas), как и в классическом SQL.
GitLab SQL Style Guide (Корпоративный стандарт ИТ-гиганта)
GitLab SQL Style Guide – публичный внутренний стандарт команды платформы данных компании GitLab (в первую очередь ориентированный на PostgreSQL и Snowflake).
Явные соединения: Полный запрет на устаревшие неявные соединения через запятую из стандарта SQL-89 (
FROM a, b WHERE a.id = b.id). Допускаются только явныеINNER JOIN,LEFT JOINс обязательным указаниемON.Запрет на
SELECT *: В промышленном и аналитическом коде всегда перечисляются только конкретные необходимые столбцы, чтобы исключить скрытые падения моделей и лишнюю нагрузку на ввод-вывод.Единые отступы: Жесткая привязка к 4 пробелам (или 2 пробелам в зависимости от репозитория) без табуляций и выравнивание подчиненных условий
AND/ORпод основнымWHERE.
Сравнение двух доминирующих школ оформления
| Параметр | Классическая школа (ANSI / Болье / учебники) | Аналитическая школа (dbt Labs / современный DWH) |
|---|---|---|
| Ключевые слова | SELECT, FROM, WHERE (ЗАГЛАВНЫЕ) | select, from, where (строчные) |
| Функции | COUNT(), ROUND(), COALESCE() | count(), round(), coalesce() |
| Поля и таблицы | customer_id, rental (строчные) | customer_id, rental (строчные) |
| Сложные выборки | Подзапросы либо CTE | Строго CTE (WITH) |
-- Классический стиль (принят в конспекте)
SELECT
customer_id,
SUM(amount) AS total_amount
FROM payment
GROUP BY customer_id;
-- Стиль dbt Labs (современный аналитический)
select
customer_id,
sum(amount) as total_amount
from payment
group by customer_id;H3¶
BETWEEN¶
оператор диапазона; сначала нижняя граница, затем верхняя 98
SELECT customer_id, rental_date
FROM rental
WHERE rental_date BETWEEN '2005-06-14' AND '2005-06-16';SELECT rental_id, customer_id, return_date
FROM rental
WHERE return_date NOT BETWEEN '2005-05-01' AND '2005-09-01';CASE¶
Expression, оператор условной логики
Проверяет истинность набора условий и в зависимости от результата проверки может возвращать тот или иной результат.
-- Синтаксис
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE resultN
END;-- Basic Case Usage
SELECT product_name,
CASE
WHEN stock_quantity > 0 THEN 'In Stock'
ELSE 'Out of Stock'
END AS stock_status
FROM products;-- Multiple Conditions
SELECT employee_name,
CASE
WHEN salary > 50000 THEN 'High Salary'
WHEN salary BETWEEN 30000 AND 50000 THEN 'Medium Salary'
ELSE 'Low Salary'
END AS salary_category
FROM employees;-- Using CASE in ORDER BY
SELECT order_id, order_date
FROM orders
ORDER BY
CASE
WHEN order_status = 'Pending' THEN 1
WHEN order_status = 'Shipped' THEN 2
ELSE 3
END;-- Using CASE in UPDATE
UPDATE employees
SET salary_category =
CASE
WHEN salary > 50000 THEN 'High Salary'
WHEN salary BETWEEN 30000 AND 50000 THEN 'Medium Salary'
ELSE 'Low Salary'
END;CAST( )¶
SELECT
-- Работа с датой и временем
CAST('2019-09-17 15:30:00' AS DATETIME), --> 2019-09-17 15:30:00
CAST('2019-09-17 15:30:00' AS DATE), --> 2019-09-17
CAST('2019-09-17 15:30:00' AS TIME), --> 15:30:00
-- Преобразование в десятичное число с заданной точностью и округлением
CAST('123.456' AS DECIMAL(5, 2)), --> 123.46
CAST(123 AS DECIMAL(5, 2)), --> 123.00
-- Преобразование в строку
CAST(12345 AS CHAR), --> '12345'
CAST('HelloWorld' AS CHAR(5)), --> 'Hello' (обрежет до 5 символов)
-- Преобразование в целые числа
CAST(-42.8 AS SIGNED), --> -43
CAST('100' AS UNSIGNED), --> 100
-- Бинарное сравнение (с учетом регистра)
(CAST('abc' AS BINARY) = 'ABC'); --> 0 (False)SELECT * FROM rental
WHERE rental_date < CAST('2005-05-25' AS DATE);COUNT( )¶
SELECT c.first_name, c.last_name, count(*)
FROM customer c
INNER JOIN rental r
ON c.customer_id = r.customer_id
GROUP BY c.first_name, c.last_name
HAVING count(*) >= 40;Чтобы не нагружать базу данных, хорошим тоном будет посчитать сначала количество строк, которое попадает под условие:
SELECT COUNT(*)
FROM large_table
WHERE your_conditions;CREATE TABLE¶
Создание таблицы 52
CREATE TABLE person(
person_id INT PRIMARY KEY AUTO_INCREMENT,
fname VARCHAR(20),
lname VARCHAR(20),
-- ...
postal_code VARCHAR(20)
);CREATE TEMPORARY TABLE¶
Создание временной таблицы 77
CREATE TEMPORARY TABLE actors_J (
actor_id smallint(5),
first_name varchar(45),
last_name varchar(45)
);
INSERT INTO actors_j
SELECT actor_id, first_name, last_name
FROM actor
WHERE last_name LIKE 'J%';CREATE VIEW¶
Создание представления (виртуальной таблицы) 78
CREATE VIEW cust_vw AS
SELECT customer_id, first_name, last_name, active
FROM customer;DATE( )¶
SELECT DATE('2003-12-31 01:02:03'); --> 2003-12-31SELECT c.first_name, c.last_name,
TIME(r.rental_date) rental_time
FROM customer c
INNER JOIN rental r
ON c.customer_id = r.customer_id
WHERE DATE(r.rental_date) = '2005-06-14';DATE_ADD( )¶
SELECT
DATE_ADD('2018-05-01', INTERVAL 1 DAY), --> '2018-05-02'
DATE_ADD('2018-05-01', INTERVAL -1 YEAR), --> '2017-05-01'
DATE_ADD('2018-12-31 23:59:59',
INTERVAL 1 DAY), --> '2019-01-01 23:59:59'
DATE_ADD('2020-12-31 23:59:59',
INTERVAL 1 SECOND), --> '2021-01-01 00:00:00'
DATE_ADD('2100-12-31 23:59:59',
INTERVAL '1:1' MINUTE_SECOND), --> '2101-01-01 00:01:00'
DATE_ADD('2025-12-31 1:58:59',
INTERVAL '23:2:2' HOUR_SECOND), --> '2026-01-01 01:01:01'
DATE_ADD('2017-01-15',
INTERVAL '9-11' YEAR_MONTH); --> '2026-12-15'DATEDIFF( )¶
SELECT DATEDIFF('2019-09-03', '2019-06-21'); --> 74
-- Игнорирует время дня в своих аргументах
SELECT DATEDIFF('2019-09-03 23:59:59', '2019-06-21 00:00:01'); --> 74DELETE¶
инструкция удалить данные 61, 152
DELETE FROM person
WHERE person_id = 2;DELETE FROM string_tbl;DESC¶
команда (describe) посмотреть столбцы и определение таблицы 53
DESC person;ключевое слово для сортировки по убыванию 87
ORDER BY last_name descDISTINCT¶
ключевое слово исключить из вывода дубликаты (оставить уникальные) 74
SELECT DISTINCT actor_id
FROM film_actor
ORDER BY actor_id;EXTRACT¶
SELECT EXTRACT(YEAR FROM '2019-09-18 22:19:05'); --> 2019
SELECT EXTRACT(MONTH FROM '2019-09-18 22:19:05'); --> 09
SELECT EXTRACT(DAY FROM '2019-09-18 22:19:05'); --> 18IN¶
оператор членства 102, 369
WHERE last_name IN ('WILLIAMS', 'DAVIS');WHERE rating NOT IN ('PG-13', 'R', 'NC-17');INNER JOIN¶
внутреннее соединение 117
SELECT c.first_name, c.last_name, a.address
FROM customer c INNER JOIN address a
ON c.address_id = a.address_id;Если имена столбцов, используемых для соединения двух таблиц, идентичны, вместо подпредложения ON можно использовать подпредложение USING
SELECT c.first_name, c.last_name, a.address
FROM customer c INNER JOIN address a
USING (address_id);INSERT INTO¶
инструкция добавить данные 57, 146
INSERT INTO person
(person_id, fname, lname, eye_color, birth_date)
VALUES (null, 'William', 'Turner', 'BR', '1972-05-27');IS NULL¶
оператор проверить является ли выражение null 108
SELECT rental_id, customer_id
FROM rental
WHERE return_date IS NULL;SELECT rental_id, customer_id, return_date
FROM rental
WHERE return_date IS NOT NULL;LEFT()¶
встроенная функция для выделения слева 104
SELECT last_name, first_name
FROM customer
WHERE left(last_name, 1) = 'Q';
-- выделение первой буквы столбца last_nameLIKE¶
оператор членства 103, 155
Используется при условных запросах, когда мы хотим узнать, соответствует ли строка определенному шаблону.
-- Синтаксис
SELECT column1, column2, ...
FROM table_name
WHERE column_name [NOT] LIKE pattern;SELECT rating FROM film WHERE title LIKE '%PET%';SELECT name, name LIKE '%y' ends_in_y
FROM category;REGEXP¶
оператор принимает регулярное выражение 106
SELECT last_name, first_name
FROM customer
WHERE last_name REGEXP '^[QY]';STR_TO_DATE( )¶
UPDATE rental
SET return_date = STR_TO_DATE('September 17, 2019', '%M', '%d', '%Y')
WHERE rental_id = 99999;TIME¶
79
SELECT c.first_name, c.last_name,
time(r.rental_date) rental_time
FROM customer c
INNER JOIN rental r
ON c.customer_id = r.customer_id
WHERE date(r.rental_date) = '2005-06-14';UPDATE¶
инструкция изменение (дополнение) данных 61, 157
UPDATE person
SET street = '1225 Tremont St.',
city = 'Boston',
state = 'MA',
country = 'USA',
postal_code = '02138'
WHERE person_id = 1;ОПЕРАТОРЫ СРАВНЕНИЯ¶
| Обозначение | Оператор | Описание |
|---|---|---|
= | Равенство | Если оба значения равны, то результат будет равен 1, иначе 0 |
<=> | Эквивалентность | Аналогичен оператору равенства, за исключением того, что результат будет равен 1 в случае сравнения NULL с NULL и 0, когда идёт сравнение любого значения с NULL |
<> или != | Неравенство | Если оба значения не равны, то результат будет равен 1, иначе 0 |
< | Меньше | Если одно значение меньше другого, то результат будет равен 1, иначе 0 |
<= | Меньше или равно | Если одно значение меньше или равно другому, то результат будет равен 1, иначе 0 |
> | Больше | Если одно значение больше другого, то результат будет равен 1, иначе 0 |
>= | Больше или равно | Если одно значение больше или равно другому, то результат будет равен 1, иначе 0 |
ЛОГИЧЕСКИЕ ОПЕРАТОРЫ¶
AND– оба условия должны быть верныOR– достаточно, чтобы выполнилось хотя бы одно условиеNOT– условие становится противоположнымXOR– выполняется только одно из двух условий, но не оба сразу
ПОДСТАНОВОЧНЫЕ СИМВОЛЫ¶
| Подстановочный символ | Соответствие |
| --------------------- | ------------------------------------ |
| _ | В точности один символ |
| % | Любое количество символов, включая 0 |
# Примеры выражений поиска
| Выражение поиска | Интерпретация |
| ---------------- | ----------------------------------------------------- |
| F% | Строка, начинающаяся с F |
| %f | Строка, заканчивающаяся f |
| %bas% | Строка, содержащая подстроку `bas` |
| __t_ | Строка из 4 символов с t в третьей позиции |
| ___-__-____ | Строка из 11 символов с дефисами в 4-й и 7-й позициях |СКАЛЯРНЫЕ ФУНКЦИИ¶
Изменение регистра:
LOWER,UPPER,INITCAPРабота с длиной и пробелами:
LENGTHИзвлечение подстрок:
LEFT,RIGHTПоиск позиции фрагмента:
POSITIONФильтрация по шаблону:
LIKE,ILIKE
RTFM¶
SELECT name, ROUND(salary * 1.2, 2)
FROM employees
WHERE department = 'IT';SELECT,FROM,WHERE– это зарезервированные Keywords (ключевые слова);ROUND– это Function (функция), которая принимает аргументы и округляет число до двух знаков после запятой;Строка
SELECT name, ROUND(salary * 1.2, 2)– это SELECT Clause (предложение);Строка
WHERE department = 'IT'– это WHERE Clause (предложение);Конструкция
ROUND(salary * 1.2, 2)– это Expression (выражение). При этом вложенный в неё кусочекsalary * 1.2– это тоже Expression. Одно выражение здесь находится внутри другого и на выходе дает готовое число;Кусочек
department = 'IT'– это Predicate (предикат / условие), возвращающий логическое да или нет;Весь запрос целиком – это один большой SELECT Statement (инструкция).
Statement¶
Инструкция (или Оператор)
Инструкция – это предложение в языке SQL, которое обычно заканчивается точкой с запятой ;. Это неделимый блок выполнения: создать объект, удалить данные, подтвердить транзакцию или вернуть результат запроса.
Инструкции делятся на группы: DDL (изменение структуры), DML (изменение данных), DCL (управление правами) и TCL (управление транзакциями).
Clause¶
Предложение
SELECT, UPDATE или DELETE).Clause не может существовать сама по себе. Это встроенный инструмент для тонкой настройки или модификации основной инструкции. Предложения всегда начинаются с определенного ключевого слова и определяют, откуда брать данные, как их фильтровать, как группировать или сколько строк возвращать. Например, весь запрос SELECT...WHERE... – это Statement, а его часть WHERE... – это Clause.
Statement– это целое, законченное Предложение (с большой буквы и с точкой в конце).Clause– это придаточное предложение (зависимый блок), входящий в состав большого.
SELECT name, salary -- Это SELECT Clause (определяет, ЧТО вернуть)
FROM employees -- Это FROM Clause (определяет, ОТКУДА взять)
WHERE salary > 50000;-- Это WHERE Clause (определяет, КАК фильтровать)При этом весь запрос целиком (от слова SELECT до точки с запятой ;) называется SELECT Statement (инструкция или оператор выбора данных).
Keywords¶
Ключевое слово (или Зарезервированное слово)
Это кирпичики и служебные команды языка. Нельзя использовать ключевые слова в качестве имен своих таблиц или столбцов (например, нельзя назвать таблицу TABLE или WHERE), иначе СУБД выдаст ошибку. Ключевые слова указывают базе данных, что именно нужно сделать с точки зрения синтаксиса (например: SELECT, FROM, AND, OR, AS, NOT, NULL).
Expression¶
Выражение
Если Statement (инструкция) – это целое законченное действие, а Predicate (предикат) – это проверка, которая отвечает только да или нет, то Expression – это вычислимый элемент, который на выходе дает готовые данные (число, строку, дату или массив).
5– простейшее выражение (константа, возвращает число 5);salary * 1.2– выражение (умножает значение из столбца на 1.2 и возвращает новую сумму);UPPER(name)– выражение (функцияUPPER()обрабатывает строку и возвращает её в верхнем регистре);CASE WHEN ... END– тоже выражение (вычисляет условия и возвращает ровно один итоговый результат).
Function¶
Функция
Функции избавляют от написания сложной логики вручную. Они бывают встроенными (предоставленными СУБД, например, для подсчета строк COUNT(), изменения регистра UPPER() или работы с датами NOW()) и пользовательскими (UDF – которые вы пишете сами). Главное отличие функции от ключевого слова – функция выполняет конкретные вычисления над переданными ей данными.
Index¶
Индекс (или Указатель)
Индекс работает как алфавитный указатель или оглавление в конце толстой книги. Вместо того чтобы перебирать всю книгу (сканировать всю таблицу на диске), СУБД смотрит в индекс, мгновенно находит физический адрес нужной строки и считывает её.
Индексы значительно ускоряют чтение данных, но замедляют запись, так как СУБД приходится обновлять их при каждом добавлении или изменении строк.
Condition¶
Condition
Логическое выражение (predicate), которое обязательно возвращает тип данных BOOLEAN (то есть результат вычисления может быть только TRUE, FALSE или NULL/UNKNOWN)
Predicate¶
Predicate
Логическое выражение, которое оценивает свойства данных и всегда возвращает логическое значение: TRUE, FALSE или NULL/UNKNOWN.
Если Expression (выражение) может возвращать числа, строки или даты, то Predicate возвращает только логический результат да / нет / не знаю. Мы используем предикаты каждый раз, когда пишем условия (например, salary > 50000, name IS NULL или age BETWEEN 18 AND 30).
Группы инструкций (DDL, DML, DCL, TCL)¶
Вся магия SQL строится на том, что все Statements (Инструкции) делятся на четыре ключевые группы в зависимости от того, какую глобальную задачу они решают. Это фундаментальная классификация для любого дата-инженера или аналитика.
| Группа | Расшифровка | Что делает? | Основные команды (Statements) |
|---|---|---|---|
| DDL | Data Definition Language | Создает, изменяет или удаляет структуру базы данных (таблицы, индексы, схемы). Работает с коробками для данных. | CREATE TABLE, ALTER TABLE, DROP TABLE, CREATE INDEX, TRUNCATE |
| DML | Data Manipulation Language | Работает с самими данными внутри этих структур. Позволяет читать, добавлять, менять или удалять строки. | SELECT, INSERT, UPDATE, DELETE |
| DCL | Data Control Language | Управляет правами доступа и безопасностью. Определяет, кто из пользователей что может делать. | GRANT (разрешить), REVOKE (отозвать права) |
| DTL | Data Transaction Language | Управляет транзакциями – объединяет несколько команд в одну неделимую группу (пакет), чтобы данные не сломались при ошибке. | COMMIT (сохранить), ROLLBACK (откатить изменения), SAVEPOINT |
Интересный нюанс: Инструкцию SELECT иногда выделяют в отдельную подгруппу – DQL (Data Query Language – язык запросов). Но чаще её все-таки относят к DML, так как она манипулирует выборкой данных.
SQL Query Order of Execution¶
Порядок написания и выполнения SQL-запроса
-- Порядок написания
SELECT -- столбцы для отображения
FROM -- таблица (-ы), из которой (-ых) нужно извлечь данные
WHERE -- фильтрация строк
GROUP BY -- разбиение строк на группы
HAVING -- фильтрация **сгруппированных** строк
ORDER BY -- столбцы для сортировки-- Порядок выполнения
SELECT -- 7: выборка полей
e.name,
d.department_name,
COUNT(o.id) as order_count
FROM employees e -- 1: определение таблиц
JOIN departments d ON e.department_id = d.id -- 2: соединения
LEFT JOIN orders o ON e.id = o.employee_id -- 3: дополнительные соединения
WHERE e.salary > 50000 -- 4: фильтрация
GROUP BY e.id, e.name, d.department_name -- 5: группировка
HAVING COUNT(o.id) > 5 -- 6: фильтрация после группировки
ORDER BY order_count DESC -- 8: сортировка
LIMIT 10; -- 9: ограничение выводаAbsent¶
Глава 7
QUOTE()
CHAR()
ASCII()
LENGHT()
POSITION()
LOCATE()
STRCMP()
LIKE как оператор сравнения
CONCAT()
INSERT()
REPLACE()
SUBSTRING()
MOD()
POW()
CEIL()
FLOOR()
ROUND()
TRUNCATE()
SIGN()
ABS()
Компоненты формата даты
Компоненты дат и времени
STR_TO_DATE()
Компоненты формата даты
CURRENT_DATE
Распространенные типы интервалов
LAST_DAY()
DAYNAME()
TIMESTAMPDIFF
DATE_FORMAT()
Смена локали
NOW()
Глава 9
IN Операторы in и not in
ALL Оператор all
ANY Оператор any
EXSTS
WITH
Обобщенные табличные выражения (Common Table Expressions, CTE) Ключевое слово: WITH
CTE — это временный именованный результирующий набор данных (виртуальная таблица), который существует только на время выполнения одного основного запроса. Он объявляется в самом начале запроса через предложение WITH.
Зачем нужны CTE (в чём их суперсила):
Читаемость сверху вниз («как рецепт»):
Вместо «матрешки» из подзапросов в блокеFROM, где запрос приходится читать из глубины наружу, CTE читается естественно — от подготовки исходных ингредиентов к итоговому блюду.**Переиспользование (DRY — Don’t Repeat Yourself):
К одной и той же CTE можно обратиться в основном запросе несколько раз (например, сджойнить её саму с собой или использовать вUNION), не дублируя код подзапроса.Цепочки зависимостей (Chaining):
Каждое следующее CTE в блокеWITHможет обращаться к любому CTE, объявленному выше него в этом же списке.Рекурсия (
WITH RECURSIVE):
Позволяет обходить иерархии, деревья и графы (например, структуру подчинения начальников и сотрудников или категории товаров с подкатегориями). Базовый анатомический синтаксис (с идеальным выравниванием):
WITH
first_cte AS (
-- Шаг 1: готовим первые данные
SELECT ...
FROM ...
),
second_cte AS (
-- Шаг 2: можем использовать данные из first_cte!
SELECT ...
FROM first_cte
WHERE ...
)
-- Шаг 3: финальный SELECT, выдающий результат пользователю
SELECT ...
FROM second_cte
INNER JOIN other_table ON ...;Возможно потребуется пробежать по предыдущим главам.
Например, в Главе 9 пришлось вспоминать
Главу 5
INNER JOIN
STRAIGHT_JOIN
Интенсив Simulative https://
DATE – Типизированный литерал
Если следовать правилу Явное лучше неявного:
Вместо '2021-01-01' профессионально использовать типизированный литерал стандарта SQL: DATE '2021-01-01'