Шпаргалка по оконным функциям и агрегатам для нумерации строк, поиска и анализа дубликатов, ранжирования результатов и аккуратного удаления лишних записей. Используется при очистке данных, аналитических запросах, построении рейтингов и подготовке данных к миграциям и отчётности.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥8🤝7
Как получить «последнюю запись на группу»?
Очень частая задача - взять последнюю запись на пользователя, заказ, сущность. Многие делают это с
Так первой будет именно самая свежая запись.
Если возможны одинаковые
Если нужно выбрать конкретные поля и избежать
Выражения из
🔥 Такой запрос часто читается проще, чем
➡️ SQL Ready | #совет
Очень частая задача - взять последнюю запись на пользователя, заказ, сущность. Многие делают это с
ROW_NUMBER(), хотя Postgres умеет проще:SELECT DISTINCT ON (user_id) *
FROM orders
ORDER BY user_id, created_at DESC;
DISTINCT ON оставляет первую строку в рамках группы, а порядок задаётся через ORDER BY:ORDER BY user_id, created_at DESC
Так первой будет именно самая свежая запись.
Если возможны одинаковые
created_at, лучше явно добавить тай-брейкер:ORDER BY user_id, created_at DESC, id DESC
Если нужно выбрать конкретные поля и избежать
SELECT *, просто укажите нужные колонки:SELECT DISTINCT ON (user_id)
user_id, id, created_at
FROM orders
ORDER BY user_id, created_at DESC, id DESC;
Выражения из
DISTINCT ON (...) обязаны быть левым префиксом ORDER BY, иначе Postgres выдаст ошибку.ROW_NUMBER(), и при подходящем индексе (user_id, created_at DESC, id DESC) может давать отличный план выполнения.Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤7🔥6🤝3
В системах бронирования одна из частых ошибок - это пересечение интервалов, когда один и тот же ресурс оказывается занят сразу несколькими пользователями.
Сегодня в задаче:
• Сравним бронирования одного ресурса между собой, не создавая дубликатов;
• Проверим пересечение временных интервалов с помощью канонического условия;
• Получим список конфликтующих бронирований, которые система должна блокировать.
Это базовый инструмент контроля данных в системах бронирования, календарях, слотах доставки и любых сервисах с ограниченными ресурсами.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥13❤5🤝4
This media is not supported in your browser
VIEW IN TELEGRAM
Этот сайт помогает анализировать структуры данных: деревья, графы, обходы и множество другого. Здесь нет решений задач или подготовкой к собеседованиям, упор именно на понимание того, как и почему всё устроено. Материал подается последовательно и концептуально, поэтому хорошо подходит даже новичкам.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤20👍9🤝7🔥2
LEFT JOIN и WHERE — классическая ловушка с NULL!
Таблицы:
Нужно получить всех пользователей и их заказы (если есть):
Если у пользователя нет заказов, поля из
Теперь типичная ошибка:
Условие в
В результате пользователи без заказов исчезают, и запрос фактически работает как
Правильный вариант — переносить условия на правую таблицу в
Теперь: пользователи без заказов остаются в результате, фильтрация применяется только к связанным строкам
Если же логика действительно требует убрать пользователей без заказов, тогда честнее писать
Так намерение запроса читается однозначно.
🔥 Условия в
➡️ SQL Ready | #практика
LEFT JOIN используют, когда нужно сохранить строки из левой таблицы, даже если в правой нет совпадений. Но одно неверное условие в WHERE — и LEFT JOIN незаметно превращается в INNER JOIN.Таблицы:
users(id, email)
orders(id, user_id, amount)
Нужно получить всех пользователей и их заказы (если есть):
SELECT
u.id,
u.email,
o.amount
FROM users u
LEFT JOIN orders o ON o.user_id = u.id;
Если у пользователя нет заказов, поля из
orders будут NULL — это ожидаемое поведение LEFT JOIN.Теперь типичная ошибка:
SELECT
u.id,
u.email,
o.amount
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.amount > 100;
Условие в
WHERE отфильтровывает строки, где o.amount IS NULL.В результате пользователи без заказов исчезают, и запрос фактически работает как
INNER JOIN.Правильный вариант — переносить условия на правую таблицу в
ON:SELECT
u.id,
u.email,
o.amount
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
AND o.amount > 100;
Теперь: пользователи без заказов остаются в результате, фильтрация применяется только к связанным строкам
orders.Если же логика действительно требует убрать пользователей без заказов, тогда честнее писать
INNER JOIN:SELECT
u.id,
u.email,
o.amount
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.amount > 100;
Так намерение запроса читается однозначно.
WHERE применяются после JOIN и могут уничтожить строки с NULL. Условия в ON влияют только на логику связывания таблиц.Please open Telegram to view this post
VIEW IN TELEGRAM
👍24❤14🔥8🤝2
This media is not supported in your browser
VIEW IN TELEGRAM
Репозиторий с понятным и структурированным разбором баз данных на русском языке. Здесь разобраны ключевые концепции SQL для MySQL и PostgreSQL, есть примеры запросов и задачи для самостоятельной работы. Отлично подходит для укрепления базы и подготовки к собеседованиям.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍8🤝5❤3
При прямом UPDATE данные теряют историю: невозможно корректно восстановить состояние сущности на дату или отследить момент изменения.
Сегодня в гайде:
• Как моделировать версионные данные через valid_from / valid_to;
• Как корректно закрывать предыдущую версию и создавать новую;
• Как получать актуальное состояние и исторические срезы без дополнительной логики.
SCD Type 2 хранит каждое изменение как отдельную версию строки с фиксированным интервалом актуальности.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍10🤝8🔥3
Например, Raft выбирает лидера через голосование, Paxos использует кворум, а Bully Algorithm назначает лидером узел с максимальным ID.
На картинке — 5 базовых алгоритмов leader election, которые используются в распределённых БД и системах координации.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤8🔥8
NULL и сравнения — почему = и <> с NULL не работают!
Таблица:
Нужно выбрать неудалённых пользователей.
Типичный, но неправильный запрос:
Запрос выполнится, но вернёт 0 строк.
Почему так — SQL выражение:
никогда не бывает TRUE.
Любое сравнение с
То же самое с отрицанием:
Результат — тоже пусто.
Правильный способ —
И обратное условие:
Частая скрытая ошибка в составных условиях:
Если
Корректная проверка «не удалён»:
Важно помнить про
Здесь логика работает ожидаемо, потому что
🔥 Практические правила: = и <> с
➡️ SQL Ready | #практика
NULL в SQL — не значение, а его отсутствие. Из-за этого любые обычные сравнения с NULL ведут себя не так, как ожидают, и часто ломают фильтрацию.Таблица:
users(id, email, deleted_at)
Нужно выбрать неудалённых пользователей.
Типичный, но неправильный запрос:
SELECT *
FROM users
WHERE deleted_at = NULL;
Запрос выполнится, но вернёт 0 строк.
Почему так — SQL выражение:
deleted_at = NULL
никогда не бывает TRUE.
Любое сравнение с
NULL (=, <>, <, >) возвращает UNKNOWN, а WHERE пропускает только TRUE.То же самое с отрицанием:
WHERE deleted_at <> NULL;
Результат — тоже пусто.
Правильный способ —
IS NULL:SELECT *
FROM users
WHERE deleted_at IS NULL;
И обратное условие:
SELECT *
FROM users
WHERE deleted_at IS NOT NULL;
IS NULL и IS NOT NULL — всегда возвращают TRUE или FALSE, никогда UNKNOWN.Частая скрытая ошибка в составных условиях:
WHERE status = 'active'
AND deleted_at <> '2026-01-01'
Если
deleted_at равен NULL, всё выражение становится UNKNOWN, и строка отбрасывается, даже если status = 'active'.Корректная проверка «не удалён»:
WHERE status = 'active'
AND deleted_at IS NULL
Важно помнить про
OR:WHERE role = 'admin'
OR deleted_at IS NULL
Здесь логика работает ожидаемо, потому что
IS NULL не возвращает UNKNOWN, а значит выражение может стать TRUE.NULL не работают в WHERE; любой UNKNOWN в WHERE — строка отбрасывается. Если строка пропала из результата — первым делом проверяй условия с NULLPlease open Telegram to view this post
VIEW IN TELEGRAM
❤15👍9🔥7🤝4
Знали, что в SQL можно получить несколько уровней агрегации за один проход по данным?
Частая задача - посчитать метрики сразу на нескольких уровнях: по стране и статусу, только по стране и общий итог. Обычно для этого пишут несколько
Каждая скобка - отдельный уровень агрегации. PostgreSQL делает это за один проход по данным, без лишних сканов.
Строка с пустыми скобками
🔥 Этот приём особенно полезен в отчётах и аналитике, где нужны totals, subtotals и детализация одновременно.
➡️ SQL Ready | #совет
Частая задача - посчитать метрики сразу на нескольких уровнях: по стране и статусу, только по стране и общий итог. Обычно для этого пишут несколько
SELECT и склеивают их UNION ALL:SELECT country, status, COUNT(*) FROM orders GROUP BY country, status
UNION ALL
SELECT country, NULL, COUNT(*) FROM orders GROUP BY country
UNION ALL
SELECT NULL, NULL, COUNT(*) FROM orders;
GROUPING SETS позволяет описать все нужные уровни агрегации в одном GROUP BY: GROUP BY GROUPING SETS ((country, status), (country), ())
Каждая скобка - отдельный уровень агрегации. PostgreSQL делает это за один проход по данным, без лишних сканов.
Строка с пустыми скобками
() - это глобальный итог. Колонки, которые не участвуют в текущем уровне, приходят как NULL:(country = NULL, status = NULL)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤20👍14🔥10🤝2