7786
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_it
🖥 Напоминалка по продвинутым функциям работы с датами!Эта шпаргалка собрала ключевые методы, которые позволяют не просто сравнивать даты, а точно извлекать нужные части, округлять по нужному уровню, форматировать для отчётов и рассчитывать интервалы в удобной форме.
➡️ SQL Ready | #шпора
😎 SQLServerCentral — крупнейшее сообщество и база знаний по Microsoft SQL Server!
Здесь публикуются ежедневные статьи, обучающие серии Stairway, подборки скриптов, обзоры книг, а также активные форумы и блоги для администраторов БД и разработчиков.
📌 Оставляю ссылочку: sqlservercentral
➡️ SQL Ready | #ресурс
🔥База платных курсов и книг по программированию на весь 2026 год!🔥
Канал новый, потому что слишком много людей ждут халявы.
Тут всё, что обычно стоит тысячи:
— Авторские курсы, которые не найти в открытом доступе
— Самые свежие книги для старта
— Всё, что нужно, чтобы за полгода вырасти от мидла до сеньора
➡️ Залетайте, пока есть доступ!
Почему после JOIN внезапно растут агрегаты!
Одна из самых неприятных ошибок в аналитическом SQL — когда запрос выглядит нормально, всё отрабатывает без ошибок, а цифры в итоге получаются больше, чем должны быть.
Классическая ситуация. Есть таблицы:
orders(id, customer_id, amount)
order_items(id, order_id, product_id, quantity)
SELECT SUM(o.amount) AS total_revenue
FROM orders o
JOIN order_items i
ON i.order_id = o.id;
order_items, то строка из orders после JOIN повторится 3 раза. И o.amount тоже попадёт в расчёт 3 раза. В итоге сумма завышается. Это как раз тот самый fan-out: одна строка размножается после JOIN.SELECT
COUNT(*) AS rows_after_join,
COUNT(DISTINCT o.id) AS unique_orders
FROM orders o
JOIN order_items i
ON i.order_id = o.id;
JOIN стало больше, чем уникальных заказов, значит у вас fan-out по уровню orders. Что делать правильно — зависит от задачи.JOIN вообще не нужен:SELECT SUM(amount)
FROM orders;
JOIN нужен только для фильтрации, например по конкретному товару, безопаснее использовать EXISTS:SELECT SUM(o.amount)
FROM orders o
WHERE EXISTS (
SELECT 1
FROM order_items i
WHERE i.order_id = o.id
AND i.product_id = 10
);
orders не ломается. Один заказ остаётся одной строкой.order_items:SELECT SUM(o.amount)
FROM orders o
JOIN (
SELECT DISTINCT order_id
FROM order_items
WHERE product_id = 10
) i ON i.order_id = o.id;
order_items:SELECT SUM(i.quantity)
FROM order_items i;
SELECT SUM(DISTINCT o.amount)
FROM orders o
JOIN order_items i
ON i.order_id = o.id;
DISTINCT сейчас всё починит, на деле — нет. Почему это плохая идея: если у двух разных заказов одинаковый amount, один из них просто схлопнется; запрос начинает давать вроде бы правдоподобный, но неверный результат.JOIN не один, а цепочка: orders — order_items — products — categoriesSELECT COUNT(*) FROM orders;
SELECT COUNT(*)
FROM orders
JOIN order_items ON order_items.order_id = orders.id;
SELECT COUNT(*)
FROM orders
JOIN order_items ON order_items.order_id = orders.id
JOIN products ON products.id = order_items.product_id;
JOIN начинаются лишние строки.JOIN, всегда держите в голове гранулярность данных. Что у вас является одной строкой: заказ, позиция заказа, клиент? Сначала определяете уровень данных — потом джойните и агрегируете.
Как вернуть строки в том же порядке, в котором пришли id?
Когда из приложения прилетает список id, обычный WHERE id = ANY(...) находит нужные строки, но порядок входного массива не сохраняет:
SELECT *
FROM users
WHERE id = ANY(ARRAY[42, 7, 99]);
WITH ORDINALITY добавляет каждой строке её позицию во входном наборе:unnest(ARRAY[42, 7, 99]) WITH ORDINALITY
ORDER BY x.ord
CASE, без ручной сортировки в коде и без лишнего постобработчика.WITH ORDINALITY — это простой способ сохранить порядок входных данных в SQL, он хорошо заходит в API и массовые выборки.
🖥 Разбираемся с FILTER — лаконичные агрегаты по условию!FILTER позволяет задать условие прямо для SUM, COUNT, AVG — без вложенных подзапросов и лишнего шума. Код получается чище, короче и проще читается.
Что важно знать:
• FILTER работает внутри агрегата — условие применяется только к нему.
• Отлично подходит для отчётных таблиц с множеством условий.
• Заменяет CASE WHEN в 90% ситуаций, где раньше казалось без него никак.
Проверка качества и целостности данных!
В больших продакшн-базах важно не только находить ошибки, но и структурировать их: проверять NULL, дубликаты, некорректные форматы и аномальные значения.
Сначала выявляем строки с пустыми ключевыми полями:
SELECT user_id, email, created_at
FROM users
WHERE user_id IS NULL
OR email IS NULL;
SELECT email, COUNT(*) AS cnt,
CASE WHEN COUNT(*)>1 THEN 'Duplicate' ELSE 'Unique' END AS status
FROM users
GROUP BY email;
SELECT order_id, total_amount
FROM orders
WHERE total_amount < 0;
Уникальность с NULL без триггеров и костылей!
Обычный UNIQUE в SQL пропускает несколько NULL, потому что NULL не считается равным другому. Из-за этого ограничение часто формально есть, а правило на самом деле не соблюдается:
UNIQUE (telegram_id)
UNIQUE даёт дыру в данных.UNIQUE NULLS NOT DISTINCT (telegram_id)
NULL обычным сравнимым значением именно для проверки уникальности.NULL уже не пройдёт, как и дубликат обычного значения.UNIQUE NULLS NOT DISTINCT (tenant_id, external_id)
nullable внешних идентификаторов, one-to-one связей, интеграционных ключей и любых полей, где NULL тоже должен быть единственным допустимым состоянием.UNIQUE NULLS NOT DISTINCT закрывает один из источников грязных данных и заменяет триггеры.
Индексы и ORDER BY DESC без лишней сортировки!
Многие думают, что для ORDER BY … DESC нужен отдельный DESC-индекс — но это не всегда так.
В PostgreSQL обычный B-tree индекс:
CREATE INDEX idx_orders_user_created
ON orders (user_id, created_at);
ORDER BY created_at DESC через backward scan, без дополнительной сортировки.user_id ASC, created_at DESC)), тогда имеет смысл явно указать направление:CREATE INDEX idx_orders_user_created_desc
ON orders (user_id, created_at DESC);
UPDATE ... FROM в PostgreSQL: как обновлять данные из другой таблицы и не поймать скрытые дубли!
Задача, которая встречается постоянно: обновить таблицу по данным из другой. Например, проставить клиентам дату последнего заказа.
Есть таблицы:
customers(id, last_order_at)
orders(id, customer_id, created_at)
UPDATE customers c
SET last_order_at = o.created_at
FROM orders o
WHERE o.customer_id = c.id;
last_order_at? Ответ — это не гарантируется.JOIN даёт несколько строк для одной записи в customers, PostgreSQL не гарантирует, какую строку он использует при обновлении.UPDATE customers c
SET last_order_at = t.max_created_at
FROM (
SELECT
customer_id,
MAX(created_at) AS max_created_at
FROM orders
GROUP BY customer_id
) t
WHERE t.customer_id = c.id;
DISTINCT ON:UPDATE customers c
SET last_order_at = t.created_at
FROM (
SELECT DISTINCT ON (customer_id)
customer_id,
created_at
FROM orders
ORDER BY customer_id, created_at DESC
) t
WHERE t.customer_id = c.id;
created_at, лучше добавить tie-breaker:ORDER BY customer_id, created_at DESC, id DESC
UPDATE customers c
SET last_order_at = (
SELECT MAX(o.created_at)
FROM orders o
WHERE o.customer_id = c.id
);
customers, и у клиентов без заказов будет NULL.UPDATE customers c
SET last_order_at = t.created_at
FROM (
SELECT customer_id, created_at
FROM orders
) t
WHERE t.customer_id = c.id;
UPDATE на SELECT с тем же JOIN и посмотрите, есть ли дубли:SELECT c.id, t.*
FROM customers c
JOIN ...
UPDATE уже небезопасен. Про индексы:CREATE INDEX idx_orders_customer_created
ON orders (customer_id, created_at);
MAX, и для ORDER BY. Итог: UPDATE ... FROM — крутой инструмент, но он не проверяет однозначность соответствия.JOIN возвращает несколько строк на одну обновляемую запись, результат не гарантируется. Сначала фиксируем одну строку на ключ — потом обновляем.
✍️ SQL for Beginners — база SQL с нуля на практике!
Репозиторий с материалами для изучения SQL с самого начала: здесь разбираются основы работы с базами данных, синтаксис запросов, JOIN-ы, фильтрация, агрегации и структура таблиц. Формат обучения построен вокруг практики, примеры запросов, задания и объяснения помогают не просто читать теорию, а сразу писать код.
Оставляю ссылочку: GitHub 📱
📂 Базовые структуры данных и их применение в системах!
Например, B-Tree используется в индексах для ускорения поиска, а Hash Table — в механизмах join’ов и кэширования.
На картинке — ключевые структуры данных и типичные сценарии их использования в реальных системах и базах данных.
Сохрани, чтобы держать под рукой!
➡️ SQL Ready | #ресурс
LIMIT без ORDER BY — почему результат нестабилен!
Есть таблица:
orders(id, customer_id, amount, created_at)
SELECT * FROM orders LIMIT 10;
ORDER BY база не обязана возвращать данные в каком-то фиксированном порядке. Сегодня это один набор строк, завтра — другой. Особенно если поменялся план выполнения или появился индекс.SELECT *
FROM orders
ORDER BY created_at DESC
LIMIT 10;
created_at.created_at, порядок между ними не детерминирован. Иногда это всплывает в самых неожиданных местах (например, в пагинации).SELECT *
FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 10;
OFFSET и его ограничения:SELECT *
FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 10 OFFSET 20;
SELECT *
FROM orders
WHERE (created_at, id) < ('2026-01-10', 1050)
ORDER BY created_at DESC, id DESC
LIMIT 10;
col1, col2) поддерживается не во всех СУБД; универсальный вариант — через OR.)SELECT *
FROM orders
ORDER BY created_at
LIMIT 1;
LIMIT отвечает только за количество. Порядок — это всегда ORDER BY. Без составного индекса (created_at, id) такие запросы на больших таблицах начинают ощутимо тормозить.
Использование расширенной статистики для повышения точности планировщика!
Бывает, что запрос очевидный, индексы есть, но PostgreSQL всё равно выбирает Seq Scan, потому что считает условия независимыми и сильно ошибается в кардинальности:
CREATE STATISTICS s_orders (dependencies)
ON user_id, status
FROM orders;
user_id почти всегда один и тот же status:ANALYZE orders;
EXPLAIN ANALYZE SELECT ...
CHECK-ограничения — валидация данных на уровне базы!CHECK позволяет задать правила, которым обязана соответствовать каждая строка в таблице. Это удобно, когда нужно гарантировать корректные значения без сторонней логики.
Представим, что мы хотим убедиться, что цена товара всегда больше нуля:
CREATE TABLE products (
product_id SERIAL PRIMARY KEY,
name TEXT,
price NUMERIC(10,2),
CHECK (price > 0)
);
ALTER TABLE discounts
ADD CONSTRAINT percent_range_chk
CHECK (percentage BETWEEN 0 AND 100);
CREATE TABLE events (
id SERIAL PRIMARY KEY,
starts_at TIMESTAMP,
ends_at TIMESTAMP,
CHECK (starts_at < ends_at)
);
CHECK проверяет только вставляемые или обновлённые строки. Если вы добавляете ограничение в таблицу с данными, указывайте NOT VALID, чтобы временно обойти проверку.
Совет на 2026 год — переходите в ML.
Пока обычные разрабы конкурируют с ИИ-копилотами, ML-инженеры эти самые нейронки создают.
В эпоху нейростей это самые востребованые люди в мире программирования. Зарплаты мидлов начинаются от 250 000 ₽, а у сеньоров в BigTech доходят до 700 000 ₽.
А чтобы освоить его всего за 4 месяца без лишней суеты — изучите канал Артема Алехина.
Его бэкграунд: Руководитель команды в Сбере, валютная удаленка. К 22 годам вышел на доход 1 000 000+ ₽ в месяц.
На канале вы найдёте:
— Всё про самые востребованные стеки(Python, ИИ-агенты, NLP) и почему математика — это не страшно, если учить только нужное.
— Как оформить резюме, чтобы оно пролетало через любые LLM-фильтры и ATS-системы прямо к тимлидам.
— Скрипты переговоров, которые помогли его ученикам прыгнуть с 0 до 360к всего за 8 месяцев.
Во времена острой нехватки ML-разработчиков, это лучшее время, чтобы перекатиться. Переходи и изучай: /channel/+qG_ihzUEkHJlOWVi
🖥 Когда система нагружена сильнее всего?
В системах с временными интервалами важно понимать не просто отдельные события, а их наложение — именно оно определяет реальную нагрузку.
Сегодня в задаче:
• Преобразуем интервалы в точки начала и конца, чтобы работать с ними как с потоком событий;
• Посчитаем текущую нагрузку через накопительную сумму по времени;
• Найдём момент максимального количества одновременных событий — пик нагрузки системы.
☕️ Годную статью нашёл на Хабре: «Как работает распределённый SQL в YDB: от запроса до выполнения»!
В этой статье:• Показано, как в YDB обрабатывается SQL-запрос — от парсинга до распределённого исполнения по узлам;
• Разбирается, как устроены планировщик, оптимизатор и механизмы шардинга при работе с большими данными;
• Объясняется, как достигаются консистентность, отказоустойчивость и масштабируемость в распределённой базе.
🔊 Продолжайте читать на Habr!
📂 Напоминалка по блокировкам и транзакциям в SQL!
Optimistic locking позволяет работать без блокировок — конфликт проверяется при записи (например, через version или updated_at). Pessimistic locking наоборот сразу ставит блокировку (SELECT ... FOR UPDATE) и заставляет другие транзакции ждать.
На картинке — как два подхода ведут себя при одновременном обновлении одной строки: в одном случае получаем conflict, в другом — очередь.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
🧐 SQL Syntax Cheat Sheet — справочник по SQL-синтаксису!
Универсальная шпаргалка по SQL, где собраны все основные конструкции языка. Всё структурировано по разделам, поэтому можно быстро найти нужный синтаксис. Формат максимально практичный: команда, пример, объяснение, что позволяет не просто смотреть, а сразу понимать, как что применяется в запросах.
Оставляю ссылочку: GitHub 📱
😎 itProger — лаконичный справочник и курс по SQL
Если нужно быстро освежить синтаксис или понять суть команд — это то, что нужно. Все основные конструкции, примеры и видеоуроки — коротко и по делу. Отлично подойдёт как шпаргалка и мини‑курс.
📌 Оставляю ссылочку: itproger.com/SQL
➡️ SQL Ready | #ресурс
📂 Напоминалка по сетям!
Каждый уровень играет важную роль: от физической передачи сигналов до приложений, с которыми мы взаимодействуем каждый день. Понимание этой модели помогает лучше разбираться в сетевых ошибках, маршрутизации и защите данных.
На картинке — 7 уровней OSI, что делает каждый из них и примеры протоколов.
Сохрани, чтобы не забыть!
➡ SQL Ready | #ресурс
👍 Mindgrasp AI — инструмент для быстрого анализа и усвоения информации!
Это AI-ассистент для обучения, который позволяет загружать документы, видео или аудио и автоматически превращать их в структурированные материалы: краткие конспекты, ответы, карточки и тесты. Также можно задавать вопросы прямо по загруженному источнику и получать точные ответы на основе его содержания.
📌 Оставляю ссылочку: mindgrasp.ai
➡️ SQL Ready | #ресурс
📂 Напоминалка по SQL вопросам!
Например, WHERE фильтрует строки до агрегации, а HAVING — уже после GROUP BY.
На картинке — основные конструкции: разница между WHERE и HAVING, оконные функции против обычной агрегации, а также основы партицирования для больших таблиц.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
😎 SQL Tutorials — структурированный набор материалов!
Здесь собраны конспекты, шпаргалки и учебные PDF по всем ключевым темам: от базовых запросов до сложных конструкций и оптимизации. Отдельно выделяется наличие большого количества материалов для подготовки к собеседованиям, сотни вопросов и разборов.
Оставляю ссылочку: GitHub 📱
Полуинтервалы вместо BETWEEN для корректных и быстрых диапазонов!BETWEEN кажется удобным, но он включает обе границы, из-за чего легко ловятся баги на датах и времени, особенно с timestamp:
WHERE created_at BETWEEN '2025-01-01' AND '2025-01-31'
WHERE created_at >= '2025-01-01'
AND created_at < '2025-02-01'
[start, end) работает предсказуемо для любых типов времени, не ломается на миллисекундах и хорошо ложится на индексы:WHERE ts >= now()
AND ts < now() + interval '1 day'
❤️ SQL Anti-Patterns — ошибки в SQL, которые допускают почти все!
Этот репозиторий разбирает типичные ошибки и плохие практики в SQL, с которыми сталкиваются разработчики в реальных проектах. Здесь показано, как не стоит писать запросы, и даются более правильные и эффективные альтернативы. Отлично подходит для оптимизации запросов и подготовки к собеседованиям.
Оставляю ссылочку: GitHub 📱
📂 Напоминалка по масштабированию баз данных!
Например, индексы ускоряют поиск данных, а шардинг позволяет распределять нагрузку между несколькими серверами.
На картинке — основные стратегии масштабирования, которые используются в реальных системах.
Сохрани, чтобы держать под рукой!
➡️ SQL Ready | #ресурс
🖥 Напоминалка по SQL-командам!
Например, GRANT даёт пользователю права на таблицу, а ROLLBACK отменяет изменения в рамках транзакции.
На картинке — 5 групп SQL-команд: от определения структуры до управления доступом.
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурс
😎 Отыскал для вас LabEx — прокачка SQL в формате игры!
Вместо скучной теории — реальные задания, которые решаешь прямо в браузере. Всё с подсказками, примерами и моментальной проверкой. Отлично, чтобы быстро вкатиться в SQL или прокачать скилл.
📌 Оставляю ссылочку: labex.io
➡️ SQL Ready | #ресурс