7786
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_it
🖥 Быстрый ориентир по SQL-командам!
Когда нужно создать таблицу или изменить её структуру — берём DDL. Хотим изменить данные внутри — используем DML. А если нужно просто вытянуть информацию — поможет DQL с её незаменимым select.
Полезно держать под рукой, чтобы не забыть!
➡️ SQL Ready | #ресурс
❤️ Полезную статью нашёл на Хабре: «Почему SUM() OVER (ORDER BY ...) иногда считает “неправильно”: разбираем оконные фреймы в SQL»!
В этой статье:• Объясняется, как на самом деле работают оконные функции в SQL и почему результаты иногда отличаются от ожидаемых;
• Разбираются ключевые типы оконных фреймов — ROWS, RANGE и GROUPS, а также их влияние на вычисления;
• Показано, как правильно задавать границы окна (UNBOUNDED PRECEDING, CURRENT ROW, FOLLOWING) для накопительных итогов, скользящих средних и аналитических запросов.
🔊 Продолжайте читать на Habr!
На Stepik добавили курс «Linux с нуля»
Этот курс закрывает всю обязательную Linux-базу для работы в IT. Подойдёт для:
- разработчиков
- девопсов и админов
- специалистов по данным и ML
- специалистов поддержки и сопровождения
- тестировщиков и безопасников
READY30»: открыть курс на Stepik
Читать полностью…
Получение top-N строк с учётом равных значений!
Иногда нужно получить не просто N строк, а все записи, которые имеют такое же значение сортировки, как и последняя строка в выборке.
Это полезно для топ-продаж, логов и аналитики.
FETCH FIRST 5 ROWS ONLY
LIMIT / FETCH возвращает ровно N строк и может «обрезать» записи с таким же значением сортировки.WITH TIES возвращает все строки, у которых значение ORDER BY совпадает с последней строкой результата:FETCH FIRST 5 ROWS WITH TIES
ORDER BY score DESC
FETCH FIRST 10 ROWS WITH TIES
WITH TIES не заменяет RANK() / DENSE_RANK(), если нужен полноценный рейтинг с номером места. Также проверьте синтаксис в вашей СУБД (например, в SQL Server используется TOP ... WITH TIES).
📂 Напоминалка по архитектуре PostgreSQL и MySQL!
PostgreSQL работает через процессы и shared memory, а системой управляет Postmaster и фоновые процессы. MySQL использует слоистую архитектуру: подключение, обработка SQL и storage engine (например InnoDB).
На картинке — основные компоненты и различия архитектуры двух популярных СУБД.
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурс
VACUUM — чистим таблицу и ускоряем работу базы!
В большинстве СУБД удалённые или обновлённые строки не удаляются мгновенно, а остаются как «мертвые» записи. Со временем это замедляет запросы и увеличивает размер таблиц — нужна очистка.
Сначала удаляем устаревшие записи из таблицы:
DELETE FROM sessions WHERE expired = true;
VACUUM ANALYZE sessions;
VACUUM VERBOSE sessions;
VACUUM поддерживает производительность и точность планов запросов.
🐱 Крутейшая статья вышла на Хабре: «Научил ИИ-агента помнить важное и забывать лишнее в SQLite»!
В этой статье:• Разбирается, почему классический RAG плохо подходит для долгоживущих AI-агентов;
• Показана архитектура когнитивной памяти на SQLite: граф узлов и рёбер, сущности, гибридный поиск и механизм разрешения конфликтов знаний;
• Объясняется, как реализовать память агента с механизмом забывания и консолидацией фактов.
🔊 Продолжайте читать на Habr!
❤️ RusauSQL — подробный учебник по SQL для тестировщиков и разработчиков!
Это большой гайд по SQL, где последовательно объясняется, как работать с базами данных и писать запросы. На сайте разбираются фундаментальные вещи: что такое SQL, как устроены таблицы и базы данных, как выполнять запросы, проверять данные и взаимодействовать с сервером через язык запросов. Отличный ресурс, если хочешь разобраться в SQL с практической стороны и понять работу баз данных.
📌 Оставляю ссылочку: rusau.net
➡️ SQL Ready | #сайт
📂 Напоминалка по SQL JOIN!
Например, LEFT JOIN позволяет получить все строки из левой таблицы, даже если соответствующих записей в правой таблице нет, а FULL OUTER JOIN возвращает все строки из обеих таблиц, заполняя отсутствующие значения NULL.
На изображении показаны 4 основных типа SQL JOIN, которые чаще всего используются при объединении данных из нескольких таблиц.
📌 Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
💡 Rows — умные таблицы с встроенным ИИ!
Сервис для работы с данными в формате таблиц (аналог Excel / Google Sheets) с интегрированными AI-инструментами. Позволяет анализировать данные, создавать формулы по описанию и подтягивать информацию из интернета и API. Подходит для аналитики, автоматизации и обработки больших массивов данных.
📌 Оставляю ссылочку: rows.com
➡️ SQL Ready | #ресурс
☕️ Полезную статью нашёл на Хабре: «Инженерная история: добавляем 3-ю СУБД в карточный процессинг»!
В этой статье:• Разобрано, зачем в высоконагруженной системе может понадобиться сразу несколько СУБД и как между ними строится абстрактный слой доступа к данным;
• Показан опыт интеграции распределённой базы данных YDB в существующую архитектуру;
• Разбираются технические нюансы: батч-операции, строгая типизация запросов, особенности драйверов и результаты нагрузочного тестирования.
🔊 Продолжайте читать на Habr!
❤️ Stepik SQL — практический курс с примерами запросов и упражнениями!
Этот репозиторий содержит структурированные задания, схемы баз данных и примеры SQL-запросов из курса на Stepik. Материалы охватывают работу с таблицами, фильтрацию, JOIN, группировки, агрегаты и другие ключевые темы языка, с акцентом на практику. Отличный ресурс для тех, кто хочет закрепить теорию через задачи.
Оставляю ссылочку: GitHub 📱
📂 Напоминалка: как выполняется SQL-запрос в базе данных!
Например, когда отправляешь SELECT, UPDATE или другой SQL, СУБД сначала обрабатывает его внутренне, а уже потом выполняет.
На схеме — путь запроса: приём — разбор (парсер) — оптимизация — выполнение — доступ к данным — буферы, транзакции и блокировки — чтение/запись (память или диск).
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурс
🖥 Oracle: работа с датой и временем!Основные функции и приёмы работы с календарными значениями в Oracle: получение текущих даты и времени на стороне БД, вычисление интервалов, смещение по месяцам, усечение до нужной гранулярности, извлечение компонентов даты, а также корректное преобразование строк в DATE и TIMESTAMP. Полезно для отчётов, аналитики, планирования, ETL-процессов и любой логики, связанной с датами и временем.
➡️ SQL Ready | #шпора
Проверка совпадений сразу по нескольким полям одной операцией!
Когда нужно сравнить строки по составному ключу, многие пишут условия с AND, которые хуже читаются и сложнее поддерживаются:
u.email = b.email AND u.phone = b.phone
(email, phone)
NULL и наличие составных индексов, оптимизация не всегда идентична AND.
🖥 Oracle SQL: основные строковые функции!Основные функции обработки строк в Oracle SQL: извлечение подстрок, определение позиции подстроки, вычисление длины строки, преобразование регистра, удаление лишних символов по краям, замена фрагментов текста и дополнение строки до заданной длины.
➡️ SQL Ready | #шпора
PostgreSQL: CONCAT_WS, если нужно нормально собрать строку из колонок с NULL!
Частая мелочь в SQL — собрать одну строку из нескольких полей. Например, имя пользователя из first_name, middle_initial, last_name.
Таблица условно такая:
users(id, first_name, middle_initial, last_name)
SELECT first_name || ' ' || middle_initial || ' ' || last_name
FROM users;
middle_initial = NULL, то результат будет не Emily Johnson, а просто NULL.CONCAT_WS:SELECT CONCAT_WS(' ', first_name, middle_initial, last_name)
FROM users;CONCAT_WS склеивает значения через разделитель и просто пропускает NULL.middle_initial = 'A': Emily A Johnson. Если middle_initial = NULL: Emily Johnson.CONCAT_WS пропускает именно NULL. Пустая строка не игнорируется.COALESCE, например так:SELECT
COALESCE(first_name || ' ', '') ||
COALESCE(middle_initial || ' ', '') ||
COALESCE(last_name, '')
FROM users;
CONCAT_WS обычно самый нормальный вариант: и короче, и читается лучше.
💡 SQL by Example — SQL-шпаргалка с примерами запросов!
Здесь разобраны реальные примеры запросов: выборки, фильтрация, JOIN-ы, подзапросы, агрегации и другие ключевые конструкции, которые чаще всего используются при работе с базами данных. Формат максимально простой: пример, объяснение, результат, поэтому можно быстро понять, как работает конкретный запрос и сразу применить его в своих задачах.
Оставляю ссылочку: GitHub 📱
Ждал меня? Признавайся…
А я уже собрал все ИИ новости и инструменты в одном telegram-канале. Как ими пользоваться, как адаптировать под разные профессии, все тут. Даже твоя бабушка поймет 😎
Подпишись. Пользуйся.
📂 Напоминалка по типам серверов!
Например, DNS Server помогает найти нужный IP по доменному имени, а Proxy Server может скрыть тебя от внешней сети.
На картинке — 6 типов серверов, которые стоит понимать каждому разработчику.
Сохрани, чтобы не забыть!
➡ SQL Ready | #ресурс
Передавайте списки значений через массивы вместо длинных IN!
Когда из приложения нужно передать список id в SQL, многие пишут IN (... , ... , ...), что увеличивает текст SQL и усложняет работу с prepared statements:
WHERE id IN (1,2,3,4,5,6,7)
ANY — это короче и позволяет избежать генерации динамического SQL:WHERE id = ANY($1)
SELECT *
FROM users
WHERE email = ANY($1);
($1::bigint[]), а также помнить, что NULL внутри массива влияет на результат сравнения.batch-запросов, API-фильтров и массовых выборок, где количество значений может сильно меняться.
SEMI JOIN через EXISTS — как корректно проверять наличие связанных строк!
Частая задача в SQL — выбрать строки из одной таблицы, если в другой таблице существует хотя бы одна связанная запись.
Таблицы:
customers(id, name)
orders(id, customer_id, created_at)
JOIN:SELECT
c.id,
c.name
FROM customers c
JOIN orders o
ON o.customer_id = c.id;
DISTINCT:SELECT DISTINCT
c.id,
c.name
FROM customers c
JOIN orders o
ON o.customer_id = c.id;
JOIN формирует строки для каждого совпадения, а DISTINCT затем устраняет повторяющиеся значения.customers, если существует хотя бы одна связанная строка в orders.EXISTS:SELECT
c.id,
c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
orders, связанной с текущим клиентом.EXISTS является естественным инструментом для проверки существования строк.SELECT
c.id,
c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
AND o.created_at >= '2025-01-01'
);
EXISTS не возвращает данные из подзапроса — он только проверяет факт существования строки.SELECT 1
SELECT *
EXISTS список выбираемых выражений не влияет на результат.EXISTS — стандартный и выразительный способ реализовать semi join. Он точно отражает намерение запроса и часто позволяет оптимизатору построить более эффективный план выполнения.
Атомарное перемещение данных между таблицами!
Иногда нужно архивировать старые данные: удалить их из основной таблицы и одновременно сохранить в архиве. Многие делают это двумя запросами (INSERT => DELETE):
DELETE FROM orders
RETURNING *
RETURNING позволяет сразу вернуть удалённые строки как результирующий набор, не выполняя повторный SELECT.WITH moved AS (...)
CTE превращает результат удаления во временный набор данных, который можно использовать в следующей операции:INSERT INTO orders_archive
SELECT * FROM moved;
🖥 Анализ средней длительности сессий пользователей по устройствам!
В этой задаче напишем SQL-запрос, который поможет вычислить среднее время сессии для пользователей на разных устройствах за последние 30 дней.
Что делаем:
• Фильтруем сессии по времени и устройствам.
• Считаем длительность каждой сессии.
• Группируем и находим среднее время по типам устройств.
Агрегирование по группам с оконными функциями!
Когда нужно посчитать агрегаты по группе и при этом сохранить исходные строки, многие делают подзапрос с GROUP BY и потом джойнят его обратно:
SUM(o.total) OVER (PARTITION BY o.user_id)
GROUP BY, ни повторное соединение:AVG(o.total) OVER (PARTITION BY o.user_id)
COUNT(*) OVER (PARTITION BY o.user_id)
Почему OFFSET может ломать производительность пагинации?OFFSET выглядит удобно для страниц, но база всё равно должна просканировать и пропустить все предыдущие строки. Поэтому чем дальше страница, тем медленнее запрос:
OFFSET 100000
OFFSET:SELECT *
FROM orders
WHERE id > :last_seen_id
ORDER BY id
LIMIT 10;
keyset-pagination — продолжать выборку от последнего значения ключа, а не пропускать строки:WHERE id > :last_seen_id
:last_seen_id — это id последней строки предыдущей страницы.created_at), добавляйте tie-breaker:ORDER BY created_at, id
WHERE (created_at, id) > (:last_seen_created_at, :last_seen_id)
Анти-JOIN — как корректно выбирать строки без связанных записей!
Частая задача в SQL — найти строки, для которых отсутствуют связанные записи в другой таблице. Это классический anti-join. Например, нужно получить клиентов, которые ни разу не сделали заказ.
Таблицы:
customers(id, name)
orders(id, customer_id, created_at)
LEFT JOIN + IS NULL:SELECT c.id, c.name
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
WHERE o.id IS NULL;
LEFT JOIN возвращает всех клиентов. Если совпадений нет, поля из orders становятся NULL, и фильтр оставляет только клиентов без заказов.NOT NULL колонку правой таблицы (обычно PK, например o.id), иначе возможны логические ошибки.NOT EXISTS (предпочтительно):SELECT c.id, c.name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
LEFT JOIN, но лучше отражает намерение, устойчив к NULL в подзапросе и часто даёт более предсказуемый план при усложнении условий. NOT IN:SELECT c.id, c.name
FROM customers c
WHERE c.id NOT IN (
SELECT customer_id
FROM orders
);
NULL, результат может стать пустым из-за трёхзначной логики SQL. Использовать этот вариант безопасно только при гарантированном NOT NULL в orders.customer_id.JOIN:SELECT c.id
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
AND o.created_at >= DATE '2026-01-01'
WHERE o.id IS NULL;
JOIN нельзя — это меняет бизнес-смысл. В таком случае корректнее использовать NOT EXISTS.orders(customer_id). При частой фильтрации по дате логичен составной индекс (customer_id, created_at).
❤️ Мега интересную статью нашёл на Хабре: «DOOMQL: DOOM-подобный многопользовательский шутер на чистом SQL»!
В этой статье:• Показано, как реализовать полноценную игру, от хранения состояния до рендеринга 3D-сцены — средствами одной лишь базы данных;
• Разобрана архитектура, игровой цикл на транзакциях и многопользовательская синхронизация через SQL;
• На реальном проекте демонстрируются неожиданные возможности СУБД далеко за пределами типичных CRUD-задач.
🔊 Продолжайте читать на Habr!
Дедупликация с приоритетом, оставляем лучшую строку!
Когда есть дубликаты по ключу (например, email), нужно сохранить запись с максимальным приоритетом — подтверждённую или самую новую.
Таблица: users(id, email, is_verified, created_at)
Сначала можно увидеть, какая строка будет считаться главной. Нумеруем строки внутри каждого email по приоритету:
SELECT id, email,
ROW_NUMBER() OVER (
PARTITION BY email
ORDER BY is_verified DESC, created_at DESC
) rn
FROM users;
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY email
ORDER BY is_verified DESC, created_at DESC
) rn
FROM users
) t
WHERE rn = 1;
SELECT DISTINCT ON (email)
id, email, is_verified, created_at
FROM users
ORDER BY email, is_verified DESC, created_at DESC;
SYSDATE в условиях — почему = SYSDATE почти никогда не то, что нужно!
В Oracle 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;
WHERE created_at >= DATE '2026-02-18'
AND created_at < DATE '2026-02-19'
DATE хранит время, прямое равенство по дате почти никогда не подходит для выборки «за день».SYSDATE.