SQL Ready | Базы Данных
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Cотрудничество: @energy_c РКН: https://clck.ru/3QREBc
Больше📈 Аналитический обзор Telegram-канала SQL Ready | Базы Данных
Канал SQL Ready | Базы Данных (@sql_ready) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 17 709 подписчиков, занимая 7 345 место в категории Технологии и приложения и 37 222 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 17 709 подписчиков.
Согласно последним данным от 17 октября, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило 691, а за последние 24 часа — 41, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 12.44%. В первые 24 часа после публикации контент обычно набирает 5.98% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 2 198 просмотров. В течение первых суток публикация набирает 1 057 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 23.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как sql, строка, users, индекс, user_id.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Авторский канал про Базы Данных и SQL
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!
Cотрудничество: @energy_c
РКН: https://clck.ru/3QREBc”
Благодаря высокой частоте обновлений (последние данные получены 18 октября, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
SYSDATE возвращает текущие дату и время с точностью до секунды. Частая ошибка — пытаться выбрать записи «за сегодня» через прямое сравнение.
Представим таблицу:
orders(id, created_at DATE)
Интуитивный вариант:
SELECT *
FROM orders
WHERE created_at = SYSDATE;
Логически кажется правильным — взять записи за текущий день. Но условие почти никогда не выполнится.
Тип DATE в Oracle хранит и дату, и время (до секунды). Чтобы совпадение произошло, created_at должен быть ровно равен текущему моменту до секунды. На практике такой запрос почти всегда возвращает пустой результат.
Попытка исправить через TRUNC:
SELECT *
FROM orders
WHERE TRUNC(created_at) = TRUNC(SYSDATE);
Работает корректно, но есть нюанс — функция применяется к колонке, поэтому обычный индекс по created_at не используется (если только нет function-based index на TRUNC(created_at)).
Правильный способ — диапазон по дате:
SELECT *
FROM orders
WHERE created_at >= TRUNC(SYSDATE)
AND created_at < TRUNC(SYSDATE) + 1;
Такое условие индекс-дружелюбное (sargable), и оптимизатор может использовать индекс. Запрос выбирает все записи за текущие сутки независимо от времени (по часовому поясу сессии/сервера БД).
Аналогично можно искать за любой день:
WHERE created_at >= DATE '2026-02-18'
AND created_at < DATE '2026-02-19'
Поскольку DATE хранит время, прямое равенство по дате почти никогда не подходит для выборки «за день».
🔥 Для выборки за день используйте полуоткрытый диапазон, а не сравнение с SYSDATE.
➡️ SQL Ready | #практикаОставляю ссылочку: GitHub 📱➡️ SQL Ready | #репозиторий
• Определим, насколько далеко тянется текущая занятость, отслеживая максимальный конец интервалов; • Найдём точки разрыва, где начинается новый независимый блок времени; • Объединим пересечения в итоговые непрерывные диапазоны.Этот приём используют для анализа сессий, расписаний, бронирований и любых временных событий, где важно видеть реальные интервалы. ➡️ SQL Ready | #задача
SELECT отвечает за выборку данных, FROM — за указание источника (таблицы), а WHERE позволяет отфильтровать строки по условию.
На картинке — основные операторы SQL, типы JOIN’ов и правильный порядок выполнения запроса внутри СУБД.
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурсnow() - created_at
Если нужно получить возраст записи в читаемом виде (годы-месяцы-дни), есть функция age(), которая учитывает календарь, а не просто секунды:
SELECT age(now(), created_at)
FROM orders;
А когда требуется число дней или часов для аналитики, интервал можно сразу привести к нужной единице:
EXTRACT(EPOCH FROM now() - created_at) / 3600
🔥 Полезно для TTL-логики, SLA-метрик, мониторинга задержек и любых задач, где время жизни записи, является ключевым параметром.
➡️ SQL Ready | #советDATE хранит дату и время одновременно. Частая задача — сравнить только по дате, игнорируя время. Многие используют TRUNC(date), но это может сильно ухудшить производительность.
Представим таблицу:
orders(id, created_at DATE)
Нужно выбрать заказы за 18 февраля 2026.
Интуитивный вариант:
SELECT *
FROM orders
WHERE TRUNC(created_at) = DATE '2026-02-18';
Логически верно, но есть проблема.
Функция применяется к колонке — поэтому обычный индекс по created_at в основном не используется, и Oracle вынужден вычислять TRUNC для множества строк, что часто приводит к полному сканированию.
Правильный способ — диапазон по дате:
SELECT *
FROM orders
WHERE created_at >= DATE '2026-02-18'
AND created_at < DATE '2026-02-19';
Теперь условие индекс-дружелюбное (sargable) — оптимизатор может использовать обычный индекс по created_at.
Этот подход корректно работает независимо от времени в поле.
TRUNC(date) полезен в SELECT или GROUP BY, когда фильтрация по индексу не критична:
SELECT
TRUNC(created_at) AS day,
COUNT(*) AS orders_count
FROM orders
GROUP BY TRUNC(created_at)
ORDER BY day;
Если всё же нужно часто фильтровать по TRUNC(created_at), можно создать функциональный индекс:
CREATE INDEX idx_orders_created_day
ON orders (TRUNC(created_at));
После этого запрос с TRUNC сможет использовать индекс.
Функция TRUNC умеет обрезать дату до разных уровней:
SELECT
TRUNC(SYSDATE) AS day,
TRUNC(SYSDATE, 'MM') AS month_start,
TRUNC(SYSDATE, 'YYYY') AS year_start
FROM dual;
Поддерживаются форматы: DD (день), MM (месяц), YYYY (год), IW (ISO-неделя) и др.
DATE хранит дату со временем, поэтому = DATE '2026-02-18' не находит все записи за день; функции над колонками мешают индексам.
🔥 Для фильтрации по дате используйте диапазоны, а TRUNC — для отображения, агрегации или вместе с функциональным индексом.
➡️ SQL Ready | #практика• Показано, как устроена учебная база, приближенная к реальным продакшен-сценариям с миллионами записей;
• Разобрано, как генерируются правдоподобные данные через имитацию работы системы, включая бронирования и жизненный цикл событий;
• Объясняется, какие задачи по SQL, аналитике и производительности можно отрабатывать на такой базе.
🔊 Продолжайте читать на Habr!➡️ SQL Ready | #статья
JOIN часто увеличивает результат или заставляет делать DISTINCT, что бьёт по производительности:
SELECT *
FROM orders o
WHERE EXISTS (
SELECT 1 FROM payments p
WHERE p.order_id = o.id
);
EXISTS останавливается на первой найденной строке и не создаёт дубликатов, поэтому обычно работает быстрее и предсказуемее:
SELECT *
FROM orders o
WHERE NOT EXISTS (
SELECT 1 FROM payments p
WHERE p.order_id = o.id
);
NOT EXISTS - наиболее корректный способ найти записи без соответствующих связанных данных.
В отличие от NOT IN он корректнее работает при наличии NULL:
SELECT *
FROM orders o
LEFT JOIN payments p ON p.order_id = o.id
WHERE p.order_id IS NULL;
🔥 LEFT JOIN + IS NULL делает то же самое логически, но чаще требует больше работы оптимизатора и может уступать по производительности на больших объёмах.
➡️ SQL Ready | #советorders(id, customer_id, amount, created_at)
Хотим увидеть все заказы и одновременно понимать, сколько денег каждый клиент потратил в сумме.
Первая мысль — посчитать через GROUP BY:
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id;
Да, сумму он посчитает. Но список заказов пропадёт — останется по одной строке на клиента.
Если коротко: GROUP BY считает по группе, но детали внутри группы выбрасывает.
Решение через оконную функцию:
SELECT
id,
customer_id,
amount,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount
FROM orders;
PARTITION BY customer_id разбивает строки на независимые окна по клиентам.
SUM(...) OVER (...) считает сумму внутри каждого окна, но строки не схлопывает — каждая остаётся на месте.
В результате каждая строка — отдельный заказ и total_amount — сумма всех заказов этого клиента.
Фильтрация по агрегату без GROUP BY — например, нужно выбрать только заказы тех клиентов, у которых суммарный оборот больше 1000:
SELECT *
FROM (
SELECT
*,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount
FROM orders
) t
WHERE total_amount > 1000;
Обратите внимание: фильтрация происходит уже после вычисления оконной функции. Никаких GROUP BY, никаких дополнительных JOIN.
Та же логика через JOIN (для сравнения):
SELECT o.*
FROM orders o
JOIN (
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
) s ON s.customer_id = o.customer_id
WHERE s.total_amount > 1000;
Работает, но выглядит тяжелее: отдельный подзапрос, джойн, дублирование таблицы.
Можно посчитать сразу несколько агрегатов по тем же окнам:
SELECT
id,
customer_id,
amount,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount,
COUNT(*) OVER (PARTITION BY customer_id) AS orders_count
FROM orders;
Получаем и общую сумму, и количество заказов клиента — прямо в каждой строке.
🔥 Используйте оконные функции, когда нужно посчитать итог по группе, но не потерять сами строки. Это базовый приём аналитического SQL, который постоянно встречается в реальных задачах.
➡️ SQL Ready | #практика