7786
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_it
📂 SQL в одной шпаргалке!
Например, SELECT, WHERE и ORDER BY отвечают за выборку, фильтрацию и сортировку данных, JOIN связывает таблицы, а GROUP BY, агрегатные и оконные функции помогают анализировать результаты запросов.
На картинке — структурированная карта SQL: от базовых запросов и объединения таблиц до CTE, подзапросов, DDL/DML/DCL/TCL, транзакций и ограничений целостности данных.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
👨💻 Koddo — сайт с теорией и практикой для обучения!
Платформа для изучения SQL через решение реальных задач прямо в браузере. На практике разбираются выборки и фильтрация, GROUP BY и HAVING, JOIN, работа с датами, подзапросы, CTE и оконные функции. Решения автоматически проверяются, а AI-ассистент может дать подсказку, не раскрывая готовый ответ.
📌 Оставляю ссылочку: koddo.ru
➡️ SQL Ready | #ресурс
Временные таблицы: различия между TEMP, CTE и материализацией данных!
В SQL существует несколько способов работать с промежуточными результатами. Основные варианты — временные таблицы, CTE через WITH и обычные подзапросы. Выбор между ними влияет на читаемость запроса, возможность повторного использования данных и работу оптимизатора.
Временная таблица создаётся внутри текущей сессии базы данных и существует до её завершения или до явного удаления. Она подходит для многоэтапной обработки данных, когда результат нужно использовать в нескольких следующих запросах.
CREATE TEMP TABLE monthly_sales AS
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
WHERE created_at >= '2026-01-01'
GROUP BY customer_id;
SELECT *
FROM monthly_sales
WHERE total_amount > 10000;
CREATE INDEX idx_monthly_sales_customer_id
ON monthly_sales(customer_id);
WITH и существует только во время выполнения одного SQL-запроса. Он помогает сделать сложную логику более читаемой и структурированной.WITH monthly_sales AS (
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
)
SELECT *
FROM monthly_sales
WHERE total_amount > 10000;
WITH active_users AS MATERIALIZED (
SELECT *
FROM users
WHERE status = 'active'
)
SELECT *
FROM active_users;
MATERIALIZED заключается в том, что PostgreSQL принудительно сохраняет результат CTE перед дальнейшей обработкой. Это может быть полезно, если один и тот же результат используется несколько раз или нужно избежать повторного выполнения тяжёлого вычисления.WITH user_stats AS MATERIALIZED (
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
)
SELECT
a.user_id,
a.orders_count
FROM user_stats a
JOIN user_stats b
ON a.user_id = b.user_id;
MATERIALIZED или NOT MATERIALIZED.WITH user_stats AS NOT MATERIALIZED (
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
)
SELECT *
FROM user_stats;
CREATE TEMP TABLE user_stats AS
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id;
CREATE INDEX idx_user_stats_user_id
ON user_stats(user_id);
ANALYZE user_stats;
ANALYZE после заполнения временной таблицы помогает PostgreSQL получить актуальную статистику и выбрать более эффективный план выполнения запроса.SELECT *
FROM (
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
) s
WHERE orders_count > 50;
Вычисляемые значения на стороне PostgreSQL!
Если значение полностью зависит от других колонок, не обязательно считать его перед каждым INSERT и UPDATE.
PostgreSQL умеет делать это сам и всегда гарантирует корректный результат.
INSERT INTO orders(price, quantity)
VALUES (100, 3);
SELECT total
FROM orders
WHERE id = 1;
total заполнится автоматически. Его нельзя случайно забыть обновить или вычислить по старой формуле.UPDATE orders
SET quantity = 5
WHERE id = 1;
SELECT total
FROM orders
WHERE id = 1;
ALTER TABLE products
ADD COLUMN search_name text
GENERATED ALWAYS AS (lower(name)) STORED;
📂 Напоминалка по выбору NoSQL баз данных для проектов!
Например, MongoDB подходит для работы с гибкими документными структурами, Redis — для высокопроизводительного кэширования и хранения данных в памяти, а Cassandra — для распределённых систем с огромными объёмами данных и высокой доступностью.
На картинке — сравнение популярных NoSQL решений, их особенностей и основных сценариев использования: от поиска и аналитики до IoT, социальных сетей, e-commerce и real-time приложений.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
🖥 Разберем ALTER — команда для изменения структуры таблиц!Добавить колонку, переименовать её, изменить тип или задать ограничение — всё это делается через ALTER TABLE. Один из важнейших инструментов в работе с готовыми таблицами.
➡️ SQL Ready | #шпора
🐱 Полезную статью нашёл на Хабре: «PostgreSQL для бэкендера: 10 фич, которыми мало пользуются, а зря»!
В этой статье:• Рассматриваются возможности PostgreSQL, которые помогают решать типовые backend-задачи на уровне базы;• Разбираются эффективные инструменты для работы с очередями, запросами, индексами и поиском;• Показывается, как использовать встроенные механизмы PostgreSQL для повышения производительности приложений.
🔊 Продолжайте читать на Habr!
➡️ SQL Ready | #статья
Почему ROW_NUMBER(), RANK() и DENSE_RANK() в SQL дают разный результат!
Есть такие оконные функции в SQL, которые выглядят почти одинаково, но используются для разных задач. ROW_NUMBER(), RANK() и DENSE_RANK() все умеют добавлять номера к строкам, но поведение меняется, когда в данных появляются одинаковые значения.
На тестовых данных разница может быть незаметной. Но в реальных задачах это влияет на рейтинги пользователей, отчёты, аналитику и любые запросы, где важно правильное место записи.
Например, есть таблица с результатами:
score
-----
100
100
90
80
ROW_NUMBER():SELECT
score,
ROW_NUMBER() OVER (
ORDER BY score DESC
) AS position
FROM results;
score | position
------+---------
100 | 1
100 | 2
90 | 3
80 | 4
ROW_NUMBER() всегда выдаёт уникальный номер для каждой строки. Даже если два значения одинаковые, они всё равно получат разные позиции.RANK():SELECT
score,
RANK() OVER (
ORDER BY score DESC
) AS position
FROM results;
score | position
------+---------
100 | 1
100 | 1
90 | 3
80 | 4
RANK() учитывает одинаковые значения и присваивает им одинаковый номер. Но после одинаковых результатов появляются пропуски. В примере выше два участника заняли первое место, поэтому следующий результат получает третье место.DENSE_RANK():SELECT
score,
DENSE_RANK() OVER (
ORDER BY score DESC
) AS position
FROM results;
score | position
------+---------
100 | 1
100 | 1
90 | 2
80 | 3
DENSE_RANK() работает похоже на RANK(), но продолжает нумерацию без пропусков. Получается простое правило: ROW_NUMBER() — когда каждая строка должна получить свой уникальный номер; RANK() — когда одинаковые значения должны иметь одинаковое место, а пропуски после них допустимы; DENSE_RANK() — когда одинаковые значения должны иметь одинаковое место, но нумерация должна идти без пропусков.ROW_NUMBER(). Если несколько строк имеют одинаковое значение для сортировки:SELECT
id,
score,
ROW_NUMBER() OVER (
ORDER BY score DESC
) AS position
FROM results;
SELECT
id,
score,
ROW_NUMBER() OVER (
ORDER BY score DESC, id
) AS position
FROM results;
ROW_NUMBER(), RANK() и DENSE_RANK() решают похожую задачу, но предназначены для разных сценариев. Главное — понимать, нужна ли вам обычная нумерация строк или именно логика рейтинга.
🤔 Learn PostgreSQL — информативное руководство!
Этот репозиторий поможет разобраться с PostgreSQL с нуля и понять, как работать с базой данных на практике. Здесь простым языком объясняются SQL-запросы, создание таблиц, связи между ними, индексы, объединения, агрегатные функции и др. Материал построен последовательно и с большим количеством примеров.
Оставляю ссылочку: GitHub 📱
Используй RETURNING как временную таблицу!
Многие после UPDATE делают отдельный SELECT, чтобы получить изменённые данные.
Но PostgreSQL уже умеет вернуть результат изменения через RETURNING.
UPDATE orders
SET status = 'paid',
paid_at = now()
WHERE id = 1001
RETURNING id, status, paid_at;
RETURNING можно сразу передавать дальше.WITH changed AS (
UPDATE orders
SET status = 'cancelled'
WHERE id = 1001
RETURNING id, status
)
INSERT INTO order_history(order_id, new_status)
SELECT id, status
FROM changed;
WITH moved AS (
DELETE FROM queue
WHERE id = 55
RETURNING *
)
INSERT INTO archive_queue
SELECT *
FROM moved;
📂 Напоминалка по шардингу данных!
Например, range-based шардинг делит данные по диапазонам значений, hash-based — распределяет записи через хэш-функцию, а consistent hashing помогает минимизировать перераспределение данных при добавлении новых нод.
На картинке — 4 алгоритма шардинга, которые полезно знать при проектировании масштабируемых систем и высоконагруженных баз данных.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
IT мероприятия 🤘
Всё самое интересное для карьеры в IT: митапы, хакатоны, конференции, стажировки и обучение.
Подписывайся 🤘
1. Москва
2. Санкт-Петербург
3. Для стажеров и студентов
👍 Годная статья вышла на Хабре: «Шардированный не значит распределённый, что важно знать, когда PostgreSQL становится мало»!
В этой статье:• Объясняется разница между шардированным PostgreSQL и настоящими распределёнными СУБД;
• Разбирается, почему Citus и похожие решения не дают полноценные ACID-гарантии для multi-shard транзакций;
• Показывается, как работают 2PC, distributed snapshot и уровни изоляции транзакций;
• На примерах объясняются проблемы consistency и eventual consistency в распределённых системах;
🔊 Продолжай читать на Habr!
🐱 PostgreSQL Cheat Sheet — удобная шпаргалка по PostgreSQL!
Этот репозиторий собрал самые важные команды и конструкции PostgreSQL в одном месте. Здесь можно быстро вспомнить синтаксис запросов, работу с таблицами, индексами, представлениями, функциями, транзакциями и др. Такая шпаргалка особенно полезна во время работы или подготовки к собеседованию.
Оставляю ссылочку: GitHub 📱
😒 Официальная библиотека промптов для Claude от Anthropic
Разработчики из Anthropic обновили и структурировали масштабный хаб готовых запросов для своей языковой модели. База создана для того, чтобы пользователи могли выжать максимум из Claude при решении прикладных и технических задач, не тратя время на самостоятельный подбор формулировок.
⚡️Внутри собраны сотни шаблонов под самые разные сценарии:
🟦Для безопасности: готовые конструкции для проверки кода на уязвимости и анализа граничных условий работы алгоритмов.
🟦Для разработчиков: шаблоны для глубокого ревью кода, автоматического поиска багов, рефакторинга, написания юнит-тестов и проектирования архитектуры.
🟦Для автоматизации и менеджмента: промпты под стратегическое планирование, парсинг неструктурированных данных, генерацию технической документации и выстраивание логики для ИИ-агентов.
🟦Разберетесь, как работают кибератаки и как грамотно защитить свои данные.
🟦Познакомитесь с направлениями и профессиями в кибербезопасности, чтобы выбрать свой трек.
🟦Получите скидку, если решите продолжить обучение в CyberYozh Academy.
Работайте с периодами как с одним значением!
Когда у записи есть start_at и end_at, проверки пересечений быстро превращаются в набор сравнений. В PostgreSQL для этого есть range types: например, tstzrange для диапазона timestamptz.
Вместо:
WHERE start_at < :end_at
AND end_at > :start_at
WHERE tstzrange(start_at, end_at, '[)')
&& tstzrange(:start_at, :end_at, '[)')
&& означает «диапазоны пересекаются». [) задаёт полуинтервал: начало включено, конец исключён, поэтому встреча до 12:00 и следующая с 12:00 не считаются пересекающимися.period @> now() -- содержит момент времени
period && :period -- пересекается
period <@ :period -- находится внутри
GiST:CREATE INDEX bookings_period_idx
ON bookings USING gist (period);
CREATE EXTENSION IF NOT EXISTS btree_gist;
ALTER TABLE bookings
ADD CONSTRAINT bookings_no_overlap
EXCLUDE USING gist (
room_id WITH =,
period WITH &&
);
🖥 Oracle — преобразование и проверка данных!Шпаргалка по преобразованию и проверке данных в Oracle: работа со строками, числами, датами, временем и Unicode. Используется для явного преобразования типов, форматирования значений, проверки корректности входных данных и обработки символьных данных.
➡️ SQL Ready | #шпора
📂 Напоминалка по SQL JOIN!
Например, SEMI JOIN позволяет получить строки, для которых есть совпадение в другой таблице, ANTI JOIN — найти строки без совпадений, а NATURAL JOIN автоматически соединяет таблицы по одноимённым столбцам.
На картинке — наглядное сравнение трёх подходов: SEMI JOIN через EXISTS, ANTI JOIN через NOT EXISTS и NATURAL JOIN, а также показано, чем SEMI JOIN отличается от обычного INNER JOIN.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
Настроил чат-бота за пару часов → заработал 9 000₽.
Просто представь, кто-то стоит в очереди на маршрутку в 8 утра чтобы успеть на “любимую” работу.
А кто-то за 3-4 часа делает чат-бота со своего ноута без привязки ко времени.
Разница в зарплате: 200 тысяч.
И нет — не надо ничего программировать.
Зачем грузить мозги кодом, если можно собрать чат-бота для бизнеса на конструкторе.
Без опыта. За 3-4 часа.
💡 Суть проста:
Берёшь клиента → Собираешь бота по шаблону → Наставник всё проверяет → Сдаёшь работу и получаешь деньги.
В первый месяц обычно выходят на доход 50–80 тыс ₽/мес, а с опытом от 180 тыс ₽ и выше. Легко совмещается с работой, учёбой, рыбалкой, семейными хлопотами… график устанавливаешь самостоятельно.
Всё, что нужно для старта — запустить бота
👉 @other_digital_bot
Там пошаговый план как стартануть и гайд по клиентам.
До 27 июля вход бесплатный.
😍 CitForum Database — большая база материалов по SQL и СУБД!
На сайте собрана крупная библиотека материалов по базам данных: SQL, проектирование БД, транзакции, индексы, оптимизация запросов и администрирование различных СУБД. Здесь можно найти статьи, учебные пособия, техническую документацию и обзоры по PostgreSQL, MySQL, Oracle, Microsoft SQL Server и другим системам управления базами данных.
📌 Оставляю ссылочку: citforum.ru
➡️ SQL Ready | #ресурс
Индексы по выражениям — ускоряем поиск по вычисляемым значениям!
Обычный индекс работает только тогда, когда база может сравнить значение напрямую с колонкой. Если в условии WHERE применяется функция к полю, оптимизатор часто не может использовать обычный индекс.
Таблица:
users(id, email)
CREATE INDEX idx_users_email
ON users(email);
SELECT *
FROM users
WHERE email = 'test@mail.com';
LOWER():SELECT *
FROM users
WHERE LOWER(email) = 'test@mail.com';
LOWER() к каждой строке, а потом сравнить результат. Обычный индекс по email для такого условия уже не подходит.CREATE INDEX idx_users_lower_email
ON users(LOWER(email));
EXPLAIN ANALYZE
SELECT *
FROM users
WHERE LOWER(email) = 'test@mail.com';
CREATE INDEX idx_orders_year
ON orders(EXTRACT(YEAR FROM created_at));
INSERT/UPDATE и занимают место.WHERE, JOIN или ORDER BY.
📂 Напоминалка по SQL JOIN и объединению данных!
Например, INNER JOIN возвращает только совпадающие записи, LEFT/RIGHT JOIN сохраняют данные одной из сторон, а FULL JOIN объединяет полный набор данных из обеих таблиц. Дополнительные проверки через NULL позволяют находить отсутствующие связи между сущностями.
На картинке — основные типы JOIN и визуальное представление того, какие строки попадут в результат выполнения запроса.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
Опа, тут бывший сеньор одного из IT-отделов Яндекса Игорь Никитин выкатил целый канал про Python — и это лучшее, что есть в рунете по теме.
Качественные гайды. Советы от известных прогеров. Тематические мемасы. Короче, ничего лишнего.
Хватит душить питона, учись его кодить: /channel/+IzIPzvoa7p40ZTUy 🐍
✍️ PostgreSQL Wiki — справочник и документация по PostgreSQL!
На сайте опубликованы статьи, руководства, инструкции и практические материалы по работе с одной из самых популярных СУБД. Здесь можно найти информацию по установке, настройке, администрированию, оптимизации производительности, репликации, резервному копированию, расширениям и др.
📌 Оставляю ссылочку: wiki.postgresql.org
➡️ SQL Ready | #ресурс
Почему CONCAT_WS в PostgreSQL часто лучше обычной конкатенации строк!
Есть такие SQL-функции, которые вроде бы выглядят слишком простыми, чтобы о них писать отдельный пост. Но именно они часто убирают кучу мелких проблем в реальных проектах, CONCAT_WS — хороший пример.
Когда работаешь с тестовыми данными, кажется, что собрать строку очень просто. Есть имя, фамилия, отчество — соединяем их через пробел и получаем красивый результат.
Обычно первый вариант выглядит так:
SELECT
first_name || ' ' || middle_name || ' ' || last_name AS full_name
FROM users;
first_name = 'John'
middle_name = NULL
last_name = 'Smith'
John Smith
NULL
COALESCE:SELECT
first_name || ' ' ||
COALESCE(middle_name || ' ', '') ||
last_name
FROM users;
SELECT
CONCAT_WS(
' ',
first_name,
middle_name,
last_name
) AS full_name
FROM users;
CONCAT_WS расшифровывается как "concatenate with separator". Первый аргумент — разделитель, который нужно использовать между значениями.John + NULL + Smith
John Smith
Germany, Berlin, Alexanderplatz 10
CONCAT_WS пропускает NULL, но пустую строку считает настоящим значением.middle_name = ''
John Smith с двойным пробелом.NULLIF(middle_name, '')
CONCAT_WS уже работает предсказуемо. На небольших примерах это кажется мелочью. Но когда у тебя несколько миллионов записей и данные собираются из разных сервисов, именно такие детали начинают влиять на качество данных и количество лишнего кода.CONCAT_WS — хороший пример того, как правильный инструмент делает SQL проще. Если нужно собрать строку из нескольких необязательных полей — часто лучше использовать её, чем вручную обрабатывать каждый NULL.
Обычное сравнение через = и != ломается, как только появляется NULL!
old_value IS DISTINCT FROM new_value
NULL никогда не равен даже другому NULL, поэтому сравнение начинает вести себя не так, как ожидается.SELECT
NULL = NULL,
NULL != NULL;
TRUE и не FALSE, а NULL. Именно из-за этого часто ломается логика сравнения.SELECT *
FROM users
WHERE old_email != new_email;
NULL, строка может просто не попасть в выборку.SELECT *
FROM users
WHERE old_email IS DISTINCT FROM new_email;
NULL корректно участвует в сравнении. PostgreSQL считает NULL обычным сравниваемым состоянием.NULL IS DISTINCT FROM NULL -- false
NULL IS DISTINCT FROM 'test' -- true
'a' IS DISTINCT FROM 'b' -- true
NULL.
📂 Напоминалка по генерации уникальных ID в SQL и распределённых системах!
Например, Auto-Increment подходит для простых SQL-проектов, где одна база данных управляет последовательностью записей, а Snowflake/UUID чаще используют в высоконагруженных системах с микросервисами, где требуется генерация ID без единой точки отказа.
На картинке — 5 основных подходов к созданию уникальных идентификаторов.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
DEFERRABLE constraints — проверяй связи в конце транзакции, а не после каждой строки!
Иногда данные нужно вставить в несколько связанных таблиц внутри одной транзакции, но порядок операций временно нарушает внешний ключ.
BEGIN;
INSERT INTO payments (id, order_id)
VALUES (1, 100);
INSERT INTO orders (id)
VALUES (100);
COMMIT;
FOREIGN KEY проверяется сразу, поэтому первый INSERT упадёт, если заказа 100 ещё нет.DEFERRABLE INITIALLY DEFERRED переносит проверку ограничения на момент COMMIT, поэтому база смотрит не на промежуточное состояние, а на итог транзакции.SET CONSTRAINTS ALL IMMEDIATE;
В PostgreSQL уникальность можно проверять не для всей таблицы, а только для части строк!
Допустим, у вас есть мягкое удаление пользователей:
SELECT email, deleted_at
FROM users;
CREATE UNIQUE INDEX users_email_uniq
ON users (email);
CREATE UNIQUE INDEX users_active_email_uniq
ON users (email)
WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX one_draft_per_user
ON posts (user_id)
WHERE status = 'draft';
📂 Напоминалка по SQL Roadmap!
Например, сначала изучают основы SQL и работу с таблицами, затем переходят к JOIN, сложным запросам, подзапросам и оконным функциям, а дальше — к проектированию баз данных, транзакциям и оптимизации.
На картинке — путь изучения от базового уровня до продвинутого: основные команды, структура базы данных, работа с данными, производительность запросов и др.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс