Я очень часто слышу от учеников одну и ту же фразу:
«Я вроде выучил синтаксис SQL…
но когда попадается задача — просто ступор.
И я не понимаю, что делать дальше».
И это абсолютно нормально.
Синтаксис — это алфавит.
Ты выучил буквы.
Но это ещё не значит, что ты умеешь читать.
Понимание SQL запросов появляется не из теории.
Оно появляется из практики.
Не из одной задачи. И даже не из десяти.
Нужно:
— решить 100 задач
— потом ещё 100
— потом ещё 100
И в какой-то момент происходит интересная вещь:
ты перестаёшь думать «а какой тут оператор?»
и начинаешь думать «какие данные мне нужны и как их связать».
SQL запросы начинают складываться автоматически.
Без паники.
Без ступора.
Это не талант.
Это не «особое мышление».
Это просто набитая рука, насмотренность и конечно же логическое мышление.
Так что если сейчас тяжело — ты не застрял.
Ты как раз в процессе обучения.
("Другого пути здесь, к сожалению или к счастью, не существует.")
Практика. Практика. Практика.
И всё обязательно встанет на свои места.
«Я вроде выучил синтаксис SQL…
но когда попадается задача — просто ступор.
И я не понимаю, что делать дальше».
И это абсолютно нормально.
Синтаксис — это алфавит.
Ты выучил буквы.
Но это ещё не значит, что ты умеешь читать.
Понимание SQL запросов появляется не из теории.
Оно появляется из практики.
Не из одной задачи. И даже не из десяти.
Нужно:
— решить 100 задач
— потом ещё 100
— потом ещё 100
И в какой-то момент происходит интересная вещь:
ты перестаёшь думать «а какой тут оператор?»
и начинаешь думать «какие данные мне нужны и как их связать».
SQL запросы начинают складываться автоматически.
Без паники.
Без ступора.
Это не талант.
Это не «особое мышление».
Это просто набитая рука, насмотренность и конечно же логическое мышление.
Так что если сейчас тяжело — ты не застрял.
Ты как раз в процессе обучения.
("Другого пути здесь, к сожалению или к счастью, не существует.")
Практика. Практика. Практика.
И всё обязательно встанет на свои места.
👍6🤔2❤1
📌 Что такое CTE в PostgreSQL?
CTE — это Common Table Expression.
На русском — общее табличное выражение.
Проще говоря: это временная таблица, которую ты создаёшь прямо внутри запроса — и потом используешь, как обычную таблицу.
📚 ✅ Когда CTE используют?
⦁ Когда запрос становится слишком сложным и трудно читается.
⦁ Когда один и тот же подзапрос используется несколько раз.
⦁ Когда хочется разбить логику на шаги — как в программе.
⦁ Когда нужно сначала отфильтровать, потом сгруппировать, потом отсортировать — и всё это понятно.
📚 🔧 Как это работает?
1. Пишешь
2. Потом пишешь основной
3. PostgreSQL вычисляет CTE один раз и использует результат дальше.
4. CTE существует только в рамках этого запроса — после него исчезает.
📌 Простой пример: Сколько заказов сделал каждый клиент?
Представим таблицу
Хочешь узнать: кто сделал больше всего заказов?
🔖 🔍 Что тут происходит?
1.
2.
3. Результат:
📚 ✅ Итог:
CTE — это Common Table Expression.
На русском — общее табличное выражение.
Проще говоря: это временная таблица, которую ты создаёшь прямо внутри запроса — и потом используешь, как обычную таблицу.
📚 ✅ Когда CTE используют?
⦁ Когда запрос становится слишком сложным и трудно читается.
⦁ Когда один и тот же подзапрос используется несколько раз.
⦁ Когда хочется разбить логику на шаги — как в программе.
⦁ Когда нужно сначала отфильтровать, потом сгруппировать, потом отсортировать — и всё это понятно.
📚 🔧 Как это работает?
1. Пишешь
WITH имя_таблицы AS (...) — и внутри скобок — обычный SELECT.2. Потом пишешь основной
SELECT, который использует это имя как таблицу.3. PostgreSQL вычисляет CTE один раз и использует результат дальше.
4. CTE существует только в рамках этого запроса — после него исчезает.
📌 Простой пример: Сколько заказов сделал каждый клиент?
Представим таблицу
orders:| id | client_id | amount |
| --- | --------- | ------ |
| 1 | 101 | 500 |
| 2 | 102 | 300 |
| 3 | 101 | 200 |
| 4 | 103 | 800 |
Хочешь узнать: кто сделал больше всего заказов?
WITH client_orders AS (
SELECT client_id, COUNT(*) as order_count
FROM orders
GROUP BY client_id
)
SELECT client_id, order_count
FROM client_orders
WHERE order_count > 1
ORDER BY order_count DESC;
🔖 🔍 Что тут происходит?
1.
WITH client_orders AS (...) — создаём временную таблицу с количеством заказов по каждому клиенту.2.
SELECT ... FROM client_orders — выбираем только тех, у кого больше 1 заказа.3. Результат:
| client_id | order_count |
| --------- | ----------- |
| 101 | 2 |
✅ Всё разбито на логические шаги.
✅ Нет вложенности.
✅ Легко изменить: например, заменить > 1 на > 2 — и всё работает.
📚 ✅ Итог:
CTE — это твой SQL-рефакторинг.
Пишите так, чтобы через месяц вы сами поняли, что делали.
🔥2
🔧 Многие ребята, когда начинают изучать SQL и базы данных, сталкиваются с одной большой проблемой.
Вроде бы:
— SQL-запросы пишем
— данные откуда-то появляются
— SELECT что-то возвращает
— работает же
Но что именно происходит под капотом и как всё это функционирует в рамках целой системы — непонятно.
Отсюда и вопросы:
— куда я вообще пишу SQL?
— откуда берутся данные?
— зачем здесь база данных?
Давайте разберёмся спокойно и по-человечески.
🗄 Что такое база данных на самом деле
База данных — это место, где хранятся данные.
Не магия. Не абстракция.
А по факту — файлы на диске сервера, в которых хранятся данные таблиц (говорим именно про реляционные БД).
Но напрямую работать с этими файлами нельзя.
("Иначе был бы полный хаос.")
⚙️ Зачем нужна СУБД
Между нами и этими файлами всегда стоит СУБД — система управления базами данных (PostgreSQL, MySQL, Oracle и т.д.).
СУБД — это ядро всей системы работы с данными.
Она:
— управляет хранением данных
— следит за целостностью
— обрабатывает SQL-запросы
— находит нужную информацию
Когда ты пишешь SQL, ты не работаешь с файлами напрямую.
Ты формулируешь запрос, а СУБД делает всю техническую работу за тебя.
Примерно как:
— ты не идёшь в архив
— ты говоришь сотруднику: «Принеси мне вот эти документы»
("Архив — это база данных, сотрудник — это СУБД.")
👥 Кто вообще взаимодействует с базой данных
Здесь важно чётко разделить роли, иначе всё быстро путается.
👤 Пользователь сайта или приложения:
Это человек, который:
— заказывает товар
— смотрит список заказов
— нажимает кнопки
Он не знает, что такое SQL. И не должен знать.
Для него существует интерфейс — сайт или приложение.
👨💻 IT-специалист
Это ты:
— аналитик
— разработчик
— инженер
— администратор БД
Ты осознанно работаешь с данными и пишешь SQL руками.
SQL — это твой инструмент управления и анализа данных.
⚙️ Приложение
Приложение — это посредник.
Оно:
— принимает действия пользователя
— формирует SQL-запрос
— отправляет его в СУБД
Но важно понимать:
приложение не “придумывает” SQL само.
Вся логика запросов заложена человеком.
🔄 Как SQL реально попадает в базу данных
SQL-запрос не “лежит” в базе данных.
Он:
— пишется IT-специалистом
— или формируется кодом приложения
— или выполняется через BI-системы
— или вводится вручную в консоли
И всегда передаётся в СУБД извне.
Типовая схема выглядит так:
Пользователь сайта → Приложение → СУБД → База данных
🌐 Как это выглядит на примере сайта
Допустим, пользователь открывает страницу со списком заказов.
Что происходит:
1️⃣ Пользователь нажал кнопку
2️⃣ Сайт отправил запрос на сервер приложения
3️⃣ Сервер сформировал SQL-запрос
4️⃣ Отправил его в СУБД
5️⃣ СУБД нашла данные в базе
6️⃣ Вернула результат приложению
7️⃣ Приложение показало данные пользователю
Пользователь видит данные.
SQL он не видит.
Но без SQL этих данных просто не существовало бы.
🧠 Важная мысль напоследок
SQL — это не просто язык запросов.
Это язык общения между людьми, приложениями и хранилищем данных.
Когда ты понимаешь:
— где физически лежат данные
— кто с ними взаимодействует
— и как SQL проходит весь путь
SQL перестаёт быть «набором команд»
и начинает выглядеть логично и осмысленно.
("А дальше уже действительно становится интересно.")
Вроде бы:
— SQL-запросы пишем
— данные откуда-то появляются
— SELECT что-то возвращает
— работает же
Но что именно происходит под капотом и как всё это функционирует в рамках целой системы — непонятно.
Отсюда и вопросы:
— куда я вообще пишу SQL?
— откуда берутся данные?
— зачем здесь база данных?
Давайте разберёмся спокойно и по-человечески.
🗄 Что такое база данных на самом деле
База данных — это место, где хранятся данные.
Не магия. Не абстракция.
А по факту — файлы на диске сервера, в которых хранятся данные таблиц (говорим именно про реляционные БД).
Но напрямую работать с этими файлами нельзя.
("Иначе был бы полный хаос.")
⚙️ Зачем нужна СУБД
Между нами и этими файлами всегда стоит СУБД — система управления базами данных (PostgreSQL, MySQL, Oracle и т.д.).
СУБД — это ядро всей системы работы с данными.
Она:
— управляет хранением данных
— следит за целостностью
— обрабатывает SQL-запросы
— находит нужную информацию
Когда ты пишешь SQL, ты не работаешь с файлами напрямую.
Ты формулируешь запрос, а СУБД делает всю техническую работу за тебя.
Примерно как:
— ты не идёшь в архив
— ты говоришь сотруднику: «Принеси мне вот эти документы»
("Архив — это база данных, сотрудник — это СУБД.")
👥 Кто вообще взаимодействует с базой данных
Здесь важно чётко разделить роли, иначе всё быстро путается.
👤 Пользователь сайта или приложения:
Это человек, который:
— заказывает товар
— смотрит список заказов
— нажимает кнопки
Он не знает, что такое SQL. И не должен знать.
Для него существует интерфейс — сайт или приложение.
👨💻 IT-специалист
Это ты:
— аналитик
— разработчик
— инженер
— администратор БД
Ты осознанно работаешь с данными и пишешь SQL руками.
SQL — это твой инструмент управления и анализа данных.
⚙️ Приложение
Приложение — это посредник.
Оно:
— принимает действия пользователя
— формирует SQL-запрос
— отправляет его в СУБД
Но важно понимать:
приложение не “придумывает” SQL само.
Вся логика запросов заложена человеком.
🔄 Как SQL реально попадает в базу данных
SQL-запрос не “лежит” в базе данных.
Он:
— пишется IT-специалистом
— или формируется кодом приложения
— или выполняется через BI-системы
— или вводится вручную в консоли
И всегда передаётся в СУБД извне.
Типовая схема выглядит так:
Пользователь сайта → Приложение → СУБД → База данных
🌐 Как это выглядит на примере сайта
Допустим, пользователь открывает страницу со списком заказов.
Что происходит:
1️⃣ Пользователь нажал кнопку
2️⃣ Сайт отправил запрос на сервер приложения
3️⃣ Сервер сформировал SQL-запрос
4️⃣ Отправил его в СУБД
5️⃣ СУБД нашла данные в базе
6️⃣ Вернула результат приложению
7️⃣ Приложение показало данные пользователю
Пользователь видит данные.
SQL он не видит.
Но без SQL этих данных просто не существовало бы.
🧠 Важная мысль напоследок
SQL — это не просто язык запросов.
Это язык общения между людьми, приложениями и хранилищем данных.
Когда ты понимаешь:
— где физически лежат данные
— кто с ними взаимодействует
— и как SQL проходит весь путь
SQL перестаёт быть «набором команд»
и начинает выглядеть логично и осмысленно.
("А дальше уже действительно становится интересно.")
👍3👏3
Что такое индекс в базе данных и как он работает?
Когда таблица в базе данных становится большой, поиск по ней начинает занимать всё больше времени. Если СУБД будет каждый раз просматривать строки одну за другой — это называется полный перебор или последовательное сканирование таблицы (Seq Scan) — производительность быстро просядет. А если нам из всей таблицы нужно выбрать только несколько строк? Становится очевидно, что сканировать все строки таблицы в таком случае не эффективно.
Именно для этого существуют индексы.
📌 Что такое индекс?
Индекс — это отдельная структура данных, которая хранится как самостоятельный файл (так же, как и файл самой таблицы).
Важно понимать:
👉 Индекс — это не часть таблицы внутри её строк.
👉 Это отдельный файл, связанный с таблицей.
По сути, индекс — это упорядоченный список значений одного или нескольких столбцов (по которым строится индекс) + указатели на соответствующие строки таблицы.
Можно представить это как предметный указатель в конце книги, в котором в алфавитном порядке перечислены термины, встречающиеся в книге, и номера страниц, на которых содержится сама информация.
📌 Как устроен индекс?
Чаще всего используется структура B-Tree (сбалансированное дерево).
В индексном файле хранятся:
- значение индексируемого поля
- ссылка (указатель) на строку таблицы
Эта ссылка содержит:
номер блока (страницы) и номер строки внутри блока
📌 Как происходит поиск по индексу?
Разберём пошагово:
1️⃣ Пользователь выполняет запрос:
SELECT * FROM users WHERE email = 'test@mail.com';
2️⃣ СУБД проверяет: есть ли индекс по полю email.
3️⃣ Если индекс есть:
происходит поиск значения 'test@mail.com' в индексном файле (быстро, за счёт специального дерева), далее находится индексная запись
4️⃣ Индексная запись содержит указатель на строку таблицы.
5️⃣ СУБД переходит по этому указателю в файл таблицы и считывает нужную строку.
💡 То есть:
- индекс помогает быстро найти где в таблице лежит нужная строка и указать на эту строку,
- а сами данные читаются уже из файла таблицы.
📌 Почему это быстрее?
Без индекса:
СУБД читает всю таблицу последовательно, то есть все строки, которые в ней есть
С индексом:
СУБД ищет значение в компактной и отсортированной структуре, затем сразу переходит к нужной строке.
В больших таблицах это может ускорить запросы в десятки и сотни раз. Но важно помнить:
Индекс — это:
✔️ ускорение чтения
❗️ но замедление вставки и обновления (индекс тоже нужно обновлять)
❗️ дополнительное место на диске (это отдельный файл)
Если коротко:
Индекс — это отдельный файл с упорядоченными значениями столбца и ссылками на строки таблицы, который позволяет быстро находить нужные данные без полного перебора.
Когда таблица в базе данных становится большой, поиск по ней начинает занимать всё больше времени. Если СУБД будет каждый раз просматривать строки одну за другой — это называется полный перебор или последовательное сканирование таблицы (Seq Scan) — производительность быстро просядет. А если нам из всей таблицы нужно выбрать только несколько строк? Становится очевидно, что сканировать все строки таблицы в таком случае не эффективно.
Именно для этого существуют индексы.
📌 Что такое индекс?
Индекс — это отдельная структура данных, которая хранится как самостоятельный файл (так же, как и файл самой таблицы).
Важно понимать:
👉 Индекс — это не часть таблицы внутри её строк.
👉 Это отдельный файл, связанный с таблицей.
По сути, индекс — это упорядоченный список значений одного или нескольких столбцов (по которым строится индекс) + указатели на соответствующие строки таблицы.
Можно представить это как предметный указатель в конце книги, в котором в алфавитном порядке перечислены термины, встречающиеся в книге, и номера страниц, на которых содержится сама информация.
📌 Как устроен индекс?
Чаще всего используется структура B-Tree (сбалансированное дерево).
В индексном файле хранятся:
- значение индексируемого поля
- ссылка (указатель) на строку таблицы
Эта ссылка содержит:
номер блока (страницы) и номер строки внутри блока
📌 Как происходит поиск по индексу?
Разберём пошагово:
1️⃣ Пользователь выполняет запрос:
SELECT * FROM users WHERE email = 'test@mail.com';
2️⃣ СУБД проверяет: есть ли индекс по полю email.
3️⃣ Если индекс есть:
происходит поиск значения 'test@mail.com' в индексном файле (быстро, за счёт специального дерева), далее находится индексная запись
4️⃣ Индексная запись содержит указатель на строку таблицы.
5️⃣ СУБД переходит по этому указателю в файл таблицы и считывает нужную строку.
💡 То есть:
- индекс помогает быстро найти где в таблице лежит нужная строка и указать на эту строку,
- а сами данные читаются уже из файла таблицы.
📌 Почему это быстрее?
Без индекса:
СУБД читает всю таблицу последовательно, то есть все строки, которые в ней есть
С индексом:
СУБД ищет значение в компактной и отсортированной структуре, затем сразу переходит к нужной строке.
В больших таблицах это может ускорить запросы в десятки и сотни раз. Но важно помнить:
Индекс — это:
✔️ ускорение чтения
❗️ но замедление вставки и обновления (индекс тоже нужно обновлять)
❗️ дополнительное место на диске (это отдельный файл)
Если коротко:
Индекс — это отдельный файл с упорядоченными значениями столбца и ссылками на строки таблицы, который позволяет быстро находить нужные данные без полного перебора.
🔥3👍1
Как я сидел и думал, почему
Писал я как-то простой SQL запрос.
Задача — выбрать заказы за январь.
Логика понятная: берём с 1 по 31 января включительно, ведь мы же знаем, что
Смотрю на результат — заказов за 31 января нет!!!
Написал простой запрос, проверил заказы за '2024-01-31' - заказы то на самом деле есть.
И тут я обнаружил что столбец с заказами кроме даты содержит еще и время, то есть находится в типе данных
В этом и заключалась проблема.
Проблема возникает не в операторе.
Проблема в типе данных.
Если order_date — это timestamp, то:
'2024-01-31' превращается в: 2024-01-31 00:00:00
И фактически диапазон выглядит так:
с 2024-01-01 00:00:00 по 2024-01-31 00:00:00
Всё, что произошло 31 января позже полуночи, уже больше верхней границы.
Как избежать этой ошибки?
1️⃣ Самый правильный способ — полуинтервал
2️⃣ Явно указать конец дня
Можно написать так:
Но:
— можно забыть миллисекунды
— можно столкнуться с разной точностью
— выглядит менее аккуратно
Использовать можно, но это не лучший стиль.
3️⃣ Привести к DATE
Если бизнес-логика действительно про дни, а не про время:
Минус — при приведении типа может не использоваться индекс.
То есть для аналитики нормально.
Для тяжёлых прод-запросов — нужно подумать.
-----------------------------------------------------------------------------------------
ВЫВОД.
Он просто честный.
Он делает ровно то, что написано.
Если тип timestamp, значит учитывается время.
Если граница — полночь, значит всё после неё уже вне диапазона.
SQL не ошибается.
Ошибаемся мы, когда забываем, что данные имеют тип.
И чем раньше начинаешь мыслить типами данных, а не просто «датами», тем меньше странных результатов в отчётах.
Работаем внимательно.
И не забываем смотреть на структуру таблицы перед тем, как писать условия.
BETWEEN вернул странный результат в PostgreSQL.Писал я как-то простой SQL запрос.
Задача — выбрать заказы за январь.
SELECT *
FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31';
Логика понятная: берём с 1 по 31 января включительно, ведь мы же знаем, что
BETWEEN включает в результат нижнюю и верхнюю границу.Смотрю на результат — заказов за 31 января нет!!!
Написал простой запрос, проверил заказы за '2024-01-31' - заказы то на самом деле есть.
И тут я обнаружил что столбец с заказами кроме даты содержит еще и время, то есть находится в типе данных
TIMESTAMP.В этом и заключалась проблема.
BETWEEN работает корректно.BETWEEN — это всегда: >= нижняя граница AND <= верхняя границаПроблема возникает не в операторе.
Проблема в типе данных.
Если order_date — это timestamp, то:
'2024-01-31' превращается в: 2024-01-31 00:00:00
И фактически диапазон выглядит так:
с 2024-01-01 00:00:00 по 2024-01-31 00:00:00
Всё, что произошло 31 января позже полуночи, уже больше верхней границы.
Как избежать этой ошибки?
1️⃣ Самый правильный способ — полуинтервал
WHERE order_date >= '2024-01-01' AND order_date < '2024-02-01';
2️⃣ Явно указать конец дня
Можно написать так:
WHERE order_date BETWEEN '2024-01-01 00:00:00' AND '2024-01-31 23:59:59';
Но:
— можно забыть миллисекунды
— можно столкнуться с разной точностью
— выглядит менее аккуратно
Использовать можно, но это не лучший стиль.
3️⃣ Привести к DATE
Если бизнес-логика действительно про дни, а не про время:
WHERE order_date::date BETWEEN '2024-01-01' AND '2024-01-31';
Минус — при приведении типа может не использоваться индекс.
То есть для аналитики нормально.
Для тяжёлых прод-запросов — нужно подумать.
-----------------------------------------------------------------------------------------
ВЫВОД.
BETWEEN — не плохой оператор.Он просто честный.
Он делает ровно то, что написано.
Если тип timestamp, значит учитывается время.
Если граница — полночь, значит всё после неё уже вне диапазона.
SQL не ошибается.
Ошибаемся мы, когда забываем, что данные имеют тип.
И чем раньше начинаешь мыслить типами данных, а не просто «датами», тем меньше странных результатов в отчётах.
Работаем внимательно.
И не забываем смотреть на структуру таблицы перед тем, как писать условия.
👍3
📌 Задача
Сколько клиентов сделали минимум 2 заказа, и какую долю они составляют от общего количества клиентов. Решаем на SQL.
У нас есть таблица orders со следующей структурой:
order_id — идентификатор заказа
customer_id — идентификатор клиента
order_date — дата заказа
🧠 Как будем мыслить
Шаг 1.
Сначала нужно посчитать, сколько заказов сделал каждый клиент.
Шаг 2.
Понять, у кого заказов ≥ 2.
Шаг 3.
Посчитать:
- общее количество клиентов
- количество клиентов с повторной покупкой
Шаг 4.
Разделить одно на другое и получить долю. Без лишней магии.
🔎 Разбор
1️⃣ CTE (WITH)
Мы создаём "временную таблицу" customer_orders,
где считаем количество заказов на каждого клиента.
2️⃣ FILTER (фишка PostgreSQL)
Конструкция:
- позволяет посчитать только тех клиентов, у которых заказов ≥ 2.
Это аккуратнее и более читаемо, чем писать SUM(CASE WHEN ...).
3️⃣ Делим одно на другое
И приводим к numeric, чтобы избежать целочисленного деления.
Добавляем ROUND(..., 2) — и получаем красивый процент в формате 0.50.
Сам SQL запрос смотри на изображении.
Сколько клиентов сделали минимум 2 заказа, и какую долю они составляют от общего количества клиентов. Решаем на SQL.
У нас есть таблица orders со следующей структурой:
order_id — идентификатор заказа
customer_id — идентификатор клиента
order_date — дата заказа
🧠 Как будем мыслить
Шаг 1.
Сначала нужно посчитать, сколько заказов сделал каждый клиент.
Шаг 2.
Понять, у кого заказов ≥ 2.
Шаг 3.
Посчитать:
- общее количество клиентов
- количество клиентов с повторной покупкой
Шаг 4.
Разделить одно на другое и получить долю. Без лишней магии.
🔎 Разбор
1️⃣ CTE (WITH)
Мы создаём "временную таблицу" customer_orders,
где считаем количество заказов на каждого клиента.
2️⃣ FILTER (фишка PostgreSQL)
Конструкция:
COUNT(*) FILTER (WHERE order_count >= 2)
- позволяет посчитать только тех клиентов, у которых заказов ≥ 2.
Это аккуратнее и более читаемо, чем писать SUM(CASE WHEN ...).
3️⃣ Делим одно на другое
COUNT(*) FILTER (WHERE order_count >= 2) / COUNT(*)
И приводим к numeric, чтобы избежать целочисленного деления.
Добавляем ROUND(..., 2) — и получаем красивый процент в формате 0.50.
Сам SQL запрос смотри на изображении.
🔥2
Какая ошибка допущена в запросе на изображении ниже ?
Anonymous Quiz
0%
Нельзя одновременно использовать AVG() и MAX() в одном запросе с GROUP BY
11%
После применения агрегатных функций сортировка возможна только по позиционному номеру столбца
78%
В ORDER BY используется столбец hire_date, который "не виден" после группировки
11%
ORDER BY должен ссылаться только на поля, входящие в GROUP BY
0%
Использование алиасов агрегатных функций запрещено при наличии GROUP BY
Декартово произведение в SQL.
4 запроса, которые могут стоить дорого.
Сегодня разберём одну опасную вещей в SQL — декартово произведение.
У нас есть таблицы:
- products — 77 строк
- order_details — 2155 строк
Теперь немного математики.
Если мы случайно получим декартово произведение, результат будет:
77 × 2155 = 165 935 строк (Сто шестьдесят пять тысяч девятьсот тридцать пять строк).
Из двух вполне обычных таблиц.
Так как же получается декартово произведение в SQL запросах ?
-----------------------------------------------
Вариант №1 — очевидный
Это честное декартово произведение.
CROSS JOIN = «каждую строку первой таблицы соединить с каждой строкой второй».
Здесь всё прозрачно.
Если вы так написали — вы сделали это осознанно.
-----------------------------------------------
Вариант №2 — старый синтаксис
Это то же самое.
Если нет условия в WHERE, это снова 77 × 2155.
Многие забывают, что запятая в FROM — это тоже JOIN.
А теперь начинается интересное.
-----------------------------------------------
Вариант №3 — ошибка невнимательности
На первый взгляд — условие есть.
Но если внимательно посмотреть: p.product_id = p.product_id
Мы сравниваем столбец сам с собой. Это всегда TRUE.
Условие никак не связывает таблицы.
А значит — снова декартово произведение.
И вот это уже опасно.
Потому что визуально кажется, что JOIN есть.
-----------------------------------------------
Вариант №4 — более современный, но та же проблема
Та же логика.
Условие соединения не использует вторую таблицу.
Это всё равно что написать: ON TRUE
И снова: 77 × 2155 = 165 935 строк.
-----------------------------------------------
Почему это действительно опасно
1️⃣ Взрыв строк
165 тысяч строк вместо ожидаемых 2155.
А если таблицы больше?
10 000 × 1 000 000 = 10 миллиардов строк.
2️⃣ Ложная аналитика
Если вы потом делаете:
SUM(price)
COUNT(*)
AVG(...)
Все значения будут очень сильно раздуты.
3️⃣ Нагрузка на сервер
База честно начинает соединять всё со всем.
- растёт время выполнения
- растёт нагрузка
- появляется seq scan + nested loop
И дальше уже вопрос к нам, а не к PostgreSQL.
4 запроса, которые могут стоить дорого.
Сегодня разберём одну опасную вещей в SQL — декартово произведение.
У нас есть таблицы:
- products — 77 строк
- order_details — 2155 строк
Теперь немного математики.
Если мы случайно получим декартово произведение, результат будет:
77 × 2155 = 165 935 строк (Сто шестьдесят пять тысяч девятьсот тридцать пять строк).
Из двух вполне обычных таблиц.
Так как же получается декартово произведение в SQL запросах ?
-----------------------------------------------
Вариант №1 — очевидный
SELECT *
FROM products
CROSS JOIN order_details;
Это честное декартово произведение.
CROSS JOIN = «каждую строку первой таблицы соединить с каждой строкой второй».
Здесь всё прозрачно.
Если вы так написали — вы сделали это осознанно.
-----------------------------------------------
Вариант №2 — старый синтаксис
SELECT *
FROM products, order_details;
Это то же самое.
Если нет условия в WHERE, это снова 77 × 2155.
Многие забывают, что запятая в FROM — это тоже JOIN.
А теперь начинается интересное.
-----------------------------------------------
Вариант №3 — ошибка невнимательности
SELECT *
FROM products p, order_details od
WHERE p.product_id = p.product_id;
На первый взгляд — условие есть.
Но если внимательно посмотреть: p.product_id = p.product_id
Мы сравниваем столбец сам с собой. Это всегда TRUE.
Условие никак не связывает таблицы.
А значит — снова декартово произведение.
И вот это уже опасно.
Потому что визуально кажется, что JOIN есть.
-----------------------------------------------
Вариант №4 — более современный, но та же проблема
SELECT *
FROM products p
JOIN order_details od ON p.product_id = p.product_id;
Та же логика.
Условие соединения не использует вторую таблицу.
Это всё равно что написать: ON TRUE
И снова: 77 × 2155 = 165 935 строк.
-----------------------------------------------
Почему это действительно опасно
1️⃣ Взрыв строк
165 тысяч строк вместо ожидаемых 2155.
А если таблицы больше?
10 000 × 1 000 000 = 10 миллиардов строк.
2️⃣ Ложная аналитика
Если вы потом делаете:
SUM(price)
COUNT(*)
AVG(...)
Все значения будут очень сильно раздуты.
3️⃣ Нагрузка на сервер
База честно начинает соединять всё со всем.
- растёт время выполнения
- растёт нагрузка
- появляется seq scan + nested loop
И дальше уже вопрос к нам, а не к PostgreSQL.
👍1😱1
Почему SQL и работа с данными в 2026 году — это уже необходимость, а не “плюс к резюме”
Мир окончательно стал цифровым.
Решения принимаются на основе данных.
Продукты строятся на данных.
ИИ обучается на данных.
И вот здесь важный момент.
Данные сами по себе обладают ценностью.
Но гораздо большую ценность имеет умение с ними работать.
📊 Факт №1. SQL — один из самых востребованных навыков
По данным hh.ru (публикация Myseldon), знание SQL упоминается примерно в 12% IT-вакансий.
Для сравнения: Linux — около 9%, Python — около 8%.
Это говорит о простом:
SQL нужен не только аналитикам.
Он нужен разработчикам, администраторам, инженерам данных.
Это инфраструктурный навык.
📈 Факт №2. Спрос на специалистов по базам данных растёт
По публикациям отраслевых изданий (например, CNews), за последние годы заметно вырос спрос на специалистов по PostgreSQL и работе с базами данных.
Компании масштабируют системы, переходят на современные СУБД, строят аналитические платформы.
А значит — нужны люди, которые понимают:
- реляционную модель
- архитектуру хранения данных
- производительность запросов
- корректность соединений
🤖 Факт №3. ИИ усиливает значение работы с данными
Да, генеративный ИИ умеет писать SQL.
Но он не отвечает за:
- корректность бизнес-логики
- качество исходных данных
- понимание, почему JOIN дал 165 935 строк вместо 2155
- контроль дублирования
- корректные границы дат
- и многое другое
ИИ ускоряет работу.
Но ответственность остаётся у человека.
💰 Факт №4. Навык напрямую влияет на доход
По данным публикаций на основе рынка вакансий, специалисты, уверенно владеющие SQL и работающие с данными, могут рассчитывать на хорошие и конкурентные зарплатные предложения (в зависимости от уровня и региона).
Важно понимать: платят не за “знание SELECT”.
Платят за умение превращать данные в решения.
🧠 Что происходит в 2026
Компании уже не экспериментируют с данными — они на них опираются.
А это значит:
- ошибки стоят дорого
- неверные агрегаты и JOIN могут влиять на стратегию
- аналитика становится частью управления
И в этой реальности SQL — это не инструмент “для айтишников”.
Это язык общения с бизнес-логикой.
💎 Вывод
В 2026 году SQL — это цифровая грамотность.
Можно пользоваться AI.
Можно пользоваться BI-инструментами.
Можно пользоваться готовыми платформами.
Но если нет понимания структуры данных и логики запросов — будет потолок.
Технологии меняются.
Данные — остаются.
А специалисты, которые умеют с ними работать, всегда будут востребованы.
Учитесь, учитесь и учитесь и будет вам счастье!
Мир окончательно стал цифровым.
Решения принимаются на основе данных.
Продукты строятся на данных.
ИИ обучается на данных.
И вот здесь важный момент.
Данные сами по себе обладают ценностью.
Но гораздо большую ценность имеет умение с ними работать.
📊 Факт №1. SQL — один из самых востребованных навыков
По данным hh.ru (публикация Myseldon), знание SQL упоминается примерно в 12% IT-вакансий.
Для сравнения: Linux — около 9%, Python — около 8%.
Это говорит о простом:
SQL нужен не только аналитикам.
Он нужен разработчикам, администраторам, инженерам данных.
Это инфраструктурный навык.
📈 Факт №2. Спрос на специалистов по базам данных растёт
По публикациям отраслевых изданий (например, CNews), за последние годы заметно вырос спрос на специалистов по PostgreSQL и работе с базами данных.
Компании масштабируют системы, переходят на современные СУБД, строят аналитические платформы.
А значит — нужны люди, которые понимают:
- реляционную модель
- архитектуру хранения данных
- производительность запросов
- корректность соединений
🤖 Факт №3. ИИ усиливает значение работы с данными
Да, генеративный ИИ умеет писать SQL.
Но он не отвечает за:
- корректность бизнес-логики
- качество исходных данных
- понимание, почему JOIN дал 165 935 строк вместо 2155
- контроль дублирования
- корректные границы дат
- и многое другое
ИИ ускоряет работу.
Но ответственность остаётся у человека.
💰 Факт №4. Навык напрямую влияет на доход
По данным публикаций на основе рынка вакансий, специалисты, уверенно владеющие SQL и работающие с данными, могут рассчитывать на хорошие и конкурентные зарплатные предложения (в зависимости от уровня и региона).
Важно понимать: платят не за “знание SELECT”.
Платят за умение превращать данные в решения.
🧠 Что происходит в 2026
Компании уже не экспериментируют с данными — они на них опираются.
А это значит:
- ошибки стоят дорого
- неверные агрегаты и JOIN могут влиять на стратегию
- аналитика становится частью управления
И в этой реальности SQL — это не инструмент “для айтишников”.
Это язык общения с бизнес-логикой.
💎 Вывод
В 2026 году SQL — это цифровая грамотность.
Можно пользоваться AI.
Можно пользоваться BI-инструментами.
Можно пользоваться готовыми платформами.
Но если нет понимания структуры данных и логики запросов — будет потолок.
Технологии меняются.
Данные — остаются.
А специалисты, которые умеют с ними работать, всегда будут востребованы.
Учитесь, учитесь и учитесь и будет вам счастье!
🔥2
Жиза: как ты объясняешь маме, чем занимаешься на работе
— Мам, я работаю с базами данных.
— А, ну как Люда из бухгалтерии, в Excel таблички вбиваешь?
— Ну… типа того, только большие.
— А-а-а, понятно. А когда женишься?
Самое смешное, что когда пытаешься объяснить нормально, становится только хуже:
— Я пишу запросы на SQL, чтобы доставать информацию из таблиц.
— А зачем её доставать, она что, упала?
— …
Бабушка (с подозрением):
— А это вообще безопасно? Эти ваши базы данных… вдруг утечка? Вон по телевизору говорят, что данные воруют.
— Бабуль, я просто смотрю, кто сколько товаров купил.
— Ох, смотри, внучок, осторожнее. А то напишут на тебя чего.
(Бабушка, меня больше беспокоит, что я могу случайно DROP TABLE написать.)
Папа (смотрит новости про нейросети):
— Сын, а вы там уже пользуетесь этим… как его… ИИ?
— Пользуемся, пап. Помогает.
— И что, теперь сам за вас запросы пишет?
— Ну, если правильно попросить — может и написать.
— Так, может, тогда ты его попроси, а сам на рыбалку?
— Пап, а если он на рыбалку захочет?
— …Ладно, работайте как знаете.
(Пап, спасибо, что беспокоишься о моём досуге.)
— Мам, я работаю с базами данных.
— А, ну как Люда из бухгалтерии, в Excel таблички вбиваешь?
— Ну… типа того, только большие.
— А-а-а, понятно. А когда женишься?
Самое смешное, что когда пытаешься объяснить нормально, становится только хуже:
— Я пишу запросы на SQL, чтобы доставать информацию из таблиц.
— А зачем её доставать, она что, упала?
— …
Бабушка (с подозрением):
— А это вообще безопасно? Эти ваши базы данных… вдруг утечка? Вон по телевизору говорят, что данные воруют.
— Бабуль, я просто смотрю, кто сколько товаров купил.
— Ох, смотри, внучок, осторожнее. А то напишут на тебя чего.
(Бабушка, меня больше беспокоит, что я могу случайно DROP TABLE написать.)
Папа (смотрит новости про нейросети):
— Сын, а вы там уже пользуетесь этим… как его… ИИ?
— Пользуемся, пап. Помогает.
— И что, теперь сам за вас запросы пишет?
— Ну, если правильно попросить — может и написать.
— Так, может, тогда ты его попроси, а сам на рыбалку?
— Пап, а если он на рыбалку захочет?
— …Ладно, работайте как знаете.
(Пап, спасибо, что беспокоишься о моём досуге.)
😁7
Что вернёт запрос, если в таблице нет ни одной строки?
SELECT AVG(age) FROM users WHERE age > 100;
SELECT AVG(age) FROM users WHERE age > 100;
Anonymous Quiz
5%
0
42%
Null
42%
Пустую таблицу
11%
Ошибку
Считаем скользящее среднее.
Есть таблица orders: каждая строка — это один заказ.
Поля:
- order_date — дата заказа,
- amount — сумма заказа.
Нужно для каждого дня посчитать средний чек за последние 3 календарных дня (включая текущий). Это помогает сгладить скачки и увидеть реальный тренд.
Разбор ключевых строк SQL запроса с изображения:
1.
Если order_date хранится как дата+время, мы отрезаем время и оставляем только день. Чтобы считать “по дням”, а не “по минутам”.
2.
Это средний чек, но не как
А
3.
Говорит базе: “считай по порядку дат”. Без порядка скользящее окно невозможно — база не поймёт, что считать “предыдущим”.
4.
Это и есть “последние 3 дня”.
Итого окно: текущий день + 2 предыдущих = 3 дня.
Почему
5.
Округляем до 2 знаков, чтобы метрика выглядела как деньги.
Есть таблица orders: каждая строка — это один заказ.
Поля:
- order_date — дата заказа,
- amount — сумма заказа.
Нужно для каждого дня посчитать средний чек за последние 3 календарных дня (включая текущий). Это помогает сгладить скачки и увидеть реальный тренд.
Разбор ключевых строк SQL запроса с изображения:
1.
order_date::date AS sale_dateЕсли order_date хранится как дата+время, мы отрезаем время и оставляем только день. Чтобы считать “по дням”, а не “по минутам”.
2.
AVG(amount) OVER (...)Это средний чек, но не как
GROUP BY.GROUP BY “схлопывает” строки в одну строку на день.А
OVER считает показатель и добавляет его к каждой строке, не ломая исходные данные.3.
ORDER BY order_date::date внутри OVERГоворит базе: “считай по порядку дат”. Без порядка скользящее окно невозможно — база не поймёт, что считать “предыдущим”.
4.
RANGE BETWEEN INTERVAL '2 days' PRECEDING AND CURRENT ROWЭто и есть “последние 3 дня”.
CURRENT ROW = текущая дата2 days PRECEDING = два календарных дня до неёИтого окно: текущий день + 2 предыдущих = 3 дня.
Почему
RANGE, а не ROWS:ROWS берёт “3 предыдущие строки”. Если в один день 50 заказов, окно будет считаться по строкам и уедет.RANGE берёт “все заказы за последние 3 календарных дня”, даже если заказов много или мало.5.
ROUND(..., 2)Округляем до 2 знаков, чтобы метрика выглядела как деньги.
Коллега спросил: можно ли сделать JOIN двух таблиц, если у них нет ключей соединения?
Многие сразу отвечают: нет.
Но правильный ответ — да, можно.
JOIN — это просто способ соединить строки двух таблиц по какому-то условию. Это условие совсем не обязано быть первичным и внешним ключом. Главное — чтобы было логическое правило, по которому строки можно сопоставить.
Например, задача из аналитики.
Есть таблица clients:
- client_id
- name
- city
И таблица managers:
- manager_id
- name
- city
Нужно найти клиентов и менеджеров, которые живут в одном городе.
Между таблицами нет ни внешнего ключа, ни прямой связи.
Но мы соединяем их по общему признаку — городу.
Важно помнить один момент:
если в городе 5 клиентов и 3 менеджера, результат будет 15 строк. SQL соединит каждого клиента с каждым менеджером. Поэтому при JOIN без ключей строки часто «умножаются».
Другой пример.
Есть таблица clients с датой выдачи карты и таблица orders с покупками. Нужно найти клиентов, которые совершали покупки в день получения карты.
Вывод простой:
JOIN — это не про ключи. JOIN — это про условие, которое логически связывает данные (хотя конечно JOIN по ключам будет наиболее эффективен).
И в реальной аналитике таблицы часто соединяют по датам, городам, диапазонам времени и другим бизнес-признакам.
Многие сразу отвечают: нет.
Но правильный ответ — да, можно.
JOIN — это просто способ соединить строки двух таблиц по какому-то условию. Это условие совсем не обязано быть первичным и внешним ключом. Главное — чтобы было логическое правило, по которому строки можно сопоставить.
Например, задача из аналитики.
Есть таблица clients:
- client_id
- name
- city
И таблица managers:
- manager_id
- name
- city
Нужно найти клиентов и менеджеров, которые живут в одном городе.
SELECT c.name AS client,
m.name AS manager,
c.city
FROM clients c
JOIN managers m ON c.city = m.city;
Между таблицами нет ни внешнего ключа, ни прямой связи.
Но мы соединяем их по общему признаку — городу.
Важно помнить один момент:
если в городе 5 клиентов и 3 менеджера, результат будет 15 строк. SQL соединит каждого клиента с каждым менеджером. Поэтому при JOIN без ключей строки часто «умножаются».
Другой пример.
Есть таблица clients с датой выдачи карты и таблица orders с покупками. Нужно найти клиентов, которые совершали покупки в день получения карты.
SELECT c.client_id,
o.order_id,
o.order_date
FROM clients c
JOIN orders o
ON c.client_id = o.client_id AND o.order_date = c.card_issue_date;
Вывод простой:
JOIN — это не про ключи. JOIN — это про условие, которое логически связывает данные (хотя конечно JOIN по ключам будет наиболее эффективен).
И в реальной аналитике таблицы часто соединяют по датам, городам, диапазонам времени и другим бизнес-признакам.
👍3❤2
ChatGPT Image 8 мар. 2026 г., 19_46_06.png
1.2 MB
Почему в PostgreSQL таблицы толстеют, даже если вы ничего не добавляете?
Представьте: вы делаете ремонт. Купили новый диван, старый решили выбросить. Но вместо того, чтобы вынести его на помойку, вы просто пододвигаете его к стенке и ставите новый рядом.
Комната та же. Места не прибавилось, места стало наоборот меньше. Дивана теперь два, только вот один из них вам уже не нужен и использовать вы его не будете.
Примерно так работает PostgreSQL, когда вы обновляете или удаляете данные.
Смотрите сами.
Допустим, есть пустая таблица: users
Вставляем туда одну строку:
В таблице одна строка. Всё хорошо.
Теперь Иван решил сменить почту. Выполняем
С точки зрения человека — мы просто исправили поле.
С точки зрения PostgreSQL — мы создали новую версию строки, а старую пометили как «мёртвую». В PostgreSQL нет ластика, которым можно просто стереть часть строки и записать туда новую информацию. Это работает иначе.
Физически в таблице теперь лежат две строки. Одна живая, одна мёртвая. Живая строка с новой информацией про Ивана, а мертвая со старой.
То же самое с
С точки зрения PostgreSQL — строка не исчезает. Она просто получает отметку «не в строю». Лежит там же, занимает место, но в выборку при написании SELECT не попадает.
Эти «мёртвые» строки и есть тот самый мусор.
Со временем, если таблица живёт активной жизнью — обновляется, удаляется, снова обновляется — мёртвых строк может становится все больше и больше.
Таблица физически раздувается, хотя полезных данных в ней может быть столько же сколько и было.
К счастью для уборки в PostgreSQL есть свой «дворник» — процесс VACUUM. Он ходит по таблицам, находит мёртвые строки и вычищает их. Свободное место становится доступным для новых строк.
Но если мусора слишком много, а дворник не успевает — таблица продолжает пухнуть.
К чему это я?
Честно сказать это опасная ситуация, требующая вмешательства так как во первых производительность начнет деградировать, во вторых это может говорить о том, что некоторые процессы внутри системы не работают или работают не так как нужно. А возможно что то мешает этим процессам нормально функционировать.
Представьте: вы делаете ремонт. Купили новый диван, старый решили выбросить. Но вместо того, чтобы вынести его на помойку, вы просто пододвигаете его к стенке и ставите новый рядом.
Комната та же. Места не прибавилось, места стало наоборот меньше. Дивана теперь два, только вот один из них вам уже не нужен и использовать вы его не будете.
Примерно так работает PostgreSQL, когда вы обновляете или удаляете данные.
Смотрите сами.
Допустим, есть пустая таблица: users
Вставляем туда одну строку:
INSERT INTO users VALUES (1, 'Иван', 'ivan@mail.ru');
В таблице одна строка. Всё хорошо.
Теперь Иван решил сменить почту. Выполняем
UPDATE:UPDATE users
SET email = 'ivan@yandex.ru'
WHERE id = 1;
С точки зрения человека — мы просто исправили поле.
С точки зрения PostgreSQL — мы создали новую версию строки, а старую пометили как «мёртвую». В PostgreSQL нет ластика, которым можно просто стереть часть строки и записать туда новую информацию. Это работает иначе.
Физически в таблице теперь лежат две строки. Одна живая, одна мёртвая. Живая строка с новой информацией про Ивана, а мертвая со старой.
То же самое с
DELETE:DELETE FROM users WHERE id = 1;
С точки зрения PostgreSQL — строка не исчезает. Она просто получает отметку «не в строю». Лежит там же, занимает место, но в выборку при написании SELECT не попадает.
Эти «мёртвые» строки и есть тот самый мусор.
Со временем, если таблица живёт активной жизнью — обновляется, удаляется, снова обновляется — мёртвых строк может становится все больше и больше.
Таблица физически раздувается, хотя полезных данных в ней может быть столько же сколько и было.
К счастью для уборки в PostgreSQL есть свой «дворник» — процесс VACUUM. Он ходит по таблицам, находит мёртвые строки и вычищает их. Свободное место становится доступным для новых строк.
Но если мусора слишком много, а дворник не успевает — таблица продолжает пухнуть.
К чему это я?
Честно сказать это опасная ситуация, требующая вмешательства так как во первых производительность начнет деградировать, во вторых это может говорить о том, что некоторые процессы внутри системы не работают или работают не так как нужно. А возможно что то мешает этим процессам нормально функционировать.
👍5
Что делать, если кажется, что SQL — это не твоё
Знакомое чувство: сидишь над задачей, смотришь на запрос…
и в голове пустота.
Читаешь условие уже третий раз.
Пробуешь написать SELECT — не получается.
Потом вроде начинает получатся, но приходит он — JOIN и все опять посыпалось. А дальше еще подзапросы выглядывают из за угла...
И в какой-то момент появляется мысль:
«Наверное, это просто не моё».
У меня это чувство было, когда я впервые столкнулся с подзапросами и оконными функциями.
Я тогда открыл задачу, посмотрел на OVER (PARTITION BY ...)
и честно подумал:
«Ну всё… дальше базового SQL я не пройду».
Потому что обычные запросы вроде стали понятны:
SELECT, JOIN, GROUP BY.
А тут внезапно новые сложности:
ROW_NUMBER() OVER (PARTITION BY ...)
И кажется, что ты читаешь какой-то другой язык.
Я несколько раз пытался решить задачу.
Не получилось.
На следующий день снова открыл пример, разобрал его по частям:
- что делает PARTITION BY
- чем это отличается от GROUP BY
- зачем нужен ORDER BY внутри окна
И постепенно картинка начала складываться.
Не сразу. Не за один вечер.
И вот что важно понять.
Когда вы учите SQL, вы не соревнуетесь с теми,
кто пишет запрос за 10 секунд.
Сегодня вы не понимаете JOIN.
Завтра начинаете понимать.
Через месяц спокойно используете оконные функции.
Это нормальный процесс.
Поэтому если иногда кажется, что SQL — это «не твоё»,
просто помни одну вещь:
Почти каждый, кто сейчас пишет сложные запросы, когда-то сидел над простым SELECT и тоже ничего не понимал.
Так что спокойно.
Ошибаться можно. Не понимать — можно.
Главное — не бросать.
Знакомое чувство: сидишь над задачей, смотришь на запрос…
и в голове пустота.
Читаешь условие уже третий раз.
Пробуешь написать SELECT — не получается.
Потом вроде начинает получатся, но приходит он — JOIN и все опять посыпалось. А дальше еще подзапросы выглядывают из за угла...
И в какой-то момент появляется мысль:
«Наверное, это просто не моё».
У меня это чувство было, когда я впервые столкнулся с подзапросами и оконными функциями.
Я тогда открыл задачу, посмотрел на OVER (PARTITION BY ...)
и честно подумал:
«Ну всё… дальше базового SQL я не пройду».
Потому что обычные запросы вроде стали понятны:
SELECT, JOIN, GROUP BY.
А тут внезапно новые сложности:
ROW_NUMBER() OVER (PARTITION BY ...)
И кажется, что ты читаешь какой-то другой язык.
Я несколько раз пытался решить задачу.
Не получилось.
Потом закрыл ноутбук и подумал:
«Ладно. Вернусь завтра».
На следующий день снова открыл пример, разобрал его по частям:
- что делает PARTITION BY
- чем это отличается от GROUP BY
- зачем нужен ORDER BY внутри окна
И постепенно картинка начала складываться.
Не сразу. Не за один вечер.
Но в какой-то момент ты вдруг ловишь себя на мысли:
«А ведь это на самом деле работает логично».
И вот что важно понять.
Когда вы учите SQL, вы не соревнуетесь с теми,
кто пишет запрос за 10 секунд.
Вы соревнуетесь только с собой вчерашним.
Но сегодня мы должны становиться лучше, чем вчера.
Сегодня вы не понимаете JOIN.
Завтра начинаете понимать.
Через месяц спокойно используете оконные функции.
Это нормальный процесс.
Поэтому если иногда кажется, что SQL — это «не твоё»,
просто помни одну вещь:
Почти каждый, кто сейчас пишет сложные запросы, когда-то сидел над простым SELECT и тоже ничего не понимал.
Так что спокойно.
Ошибаться можно. Не понимать — можно.
Главное — не бросать.
👍5❤2