Получение первых N строк с FETCH FIRST, постраничная выборка с FETCH NEXT и OFFSET, включение строк с одинаковыми значениями сортировки через WITH TIES, ограничение результата в процентах с PERCENT, использование ROWNUM, а также нумерация и ранжирование с ROW_NUMBER() и DENSE_RANK(). Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍11❤6
This media is not supported in your browser
VIEW IN TELEGRAM
Сайт с учебными и справочными материалами по SQL и работе с реляционными базами данных. Подойдёт для изучения основных конструкций языка, понимания принципов построения запросов и повторения теории. Ресурс пригодится начинающим аналитикам и разработчикам, а также тем, кому нужен дополнительный справочник по SQL во время обучения или работы с базами данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥9❤6
Почему BETWEEN может незаметно исключать данные при фильтрации по датам!
При работе с временными диапазонами часто используют
Допустим, есть таблица заказов:
Нужно получить заказы за сентябрь 2026 года. На первый взгляд подходит запрос:
Однако
Например, запись со временем
Но это тоже ненадёжный вариант. Если колонка поддерживает дробные доли секунды, запись
Для временных интервалов практичнее использовать полуоткрытый диапазон:
Такой запрос включает все значения за сентябрь независимо от точности хранения времени и исключает записи следующего месяца.
Ещё одно преимущество — соседние интервалы не пересекаются. Например, при последовательной обработке данных можно использовать:
При условии, что следующая выборка начинается с предыдущего
Такой подход также хорошо сочетается с обычным B-tree индексом:
Поскольку фильтрация выполняется непосредственно по индексируемой колонке, оптимизатор может использовать диапазонное сканирование индекса. При использовании типов с часовыми поясами границы необходимо задавать в соответствии с нужной временной зоной, особенно если речь идёт о календарных днях.
🔥 Для фильтрации по временным интервалам условия
➡️ SQL Ready | #практика
При работе с временными диапазонами часто используют
BETWEEN. Но если колонка хранит дату вместе со временем, такой фильтр может возвращать не все ожидаемые записи.Допустим, есть таблица заказов:
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
created_at TIMESTAMP NOT NULL,
amount DECIMAL(12, 2)
);
Нужно получить заказы за сентябрь 2026 года. На первый взгляд подходит запрос:
SELECT *
FROM orders
WHERE created_at BETWEEN
TIMESTAMP '2026-09-01 00:00:00'
AND TIMESTAMP '2026-09-30 00:00:00';
Однако
BETWEEN включает обе границы диапазона и эквивалентен сочетанию >= и <=. Поэтому запрос вернёт записи с 1 сентября по начало 30 сентября, но исключит все заказы, созданные позднее полуночи последнего дня месяца.Например, запись со временем
2026-09-30 15:30:00 не попадёт в результат. Иногда верхнюю границу пытаются исправить вручную:WHERE created_at BETWEEN
TIMESTAMP '2026-09-01 00:00:00'
AND TIMESTAMP '2026-09-30 23:59:59';
Но это тоже ненадёжный вариант. Если колонка поддерживает дробные доли секунды, запись
2026-09-30 23:59:59.500 окажется за пределами диапазона.Для временных интервалов практичнее использовать полуоткрытый диапазон:
SELECT *
FROM orders
WHERE created_at >= TIMESTAMP '2026-09-01 00:00:00'
AND created_at < TIMESTAMP '2026-10-01 00:00:00';
Такой запрос включает все значения за сентябрь независимо от точности хранения времени и исключает записи следующего месяца.
Ещё одно преимущество — соседние интервалы не пересекаются. Например, при последовательной обработке данных можно использовать:
WHERE created_at >= :date_from
AND created_at < :date_to;
При условии, что следующая выборка начинается с предыдущего
date_to, каждая запись на границе интервалов попадёт ровно в один диапазон.Такой подход также хорошо сочетается с обычным B-tree индексом:
CREATE INDEX idx_orders_created_at
ON orders (created_at);
Поскольку фильтрация выполняется непосредственно по индексируемой колонке, оптимизатор может использовать диапазонное сканирование индекса. При использовании типов с часовыми поясами границы необходимо задавать в соответствии с нужной временной зоной, особенно если речь идёт о календарных днях.
>= и < обычно надёжнее, чем BETWEEN. Полуоткрытые диапазоны не зависят от точности TIMESTAMP, не пересекаются на границах и удобны для отчётности, пакетной обработки и инкрементальной загрузки данных.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤6👍4
Например, Event-Driven обеспечивает асинхронное распространение изменений между сервисами, а CQRS позволяет разделять операции чтения и записи с независимым обновлением моделей данных.
На картинке — 4 архитектурных подхода, которые помогают управлять согласованностью данных, снижать связанность компонентов и масштабировать распределённые системы.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤7👍4
Требуются 7 человек, чтобы помогали собирать чат-ботов для бизнеса по блокам, как лего.
Стоит попробовать, если хочешь:
✅ ЗП: от 5000-9000₽ за 1-2 вечера.
✅ Занятость: 3–4 часа в день.
✅ Свободный график.
Опыт в разработке не требуется.
Всё, что нужно для старта — запустить обучение
👉@pautov_techspec_bot
И пройти инструктаж.
Стоит попробовать, если хочешь:
✅ ЗП: от 5000-9000₽ за 1-2 вечера.
✅ Занятость: 3–4 часа в день.
✅ Свободный график.
Опыт в разработке не требуется.
Всё, что нужно для старта — запустить обучение
👉@pautov_techspec_bot
И пройти инструктаж.
👎1
Переносите строки без промежуточной выборки!
Обычно архивирование делают в два этапа: сначала копируют записи, затем удаляют исходные. В PostgreSQL можно связать эти действия через
А теперь используем возвращённые строки как источник для вставки:
Всё выполняется одним оператором SQL. Если вставка в архив завершится ошибкой, удаление тоже откатится.
При этом можно преобразовать данные перед архивированием:
🔥
➡️ SQL Ready | #совет
Обычно архивирование делают в два этапа: сначала копируют записи, затем удаляют исходные. В PostgreSQL можно связать эти действия через
DELETE ... RETURNING.-- Удаляем строки и сразу получаем их содержимое
DELETE FROM events
WHERE created_at < DATE '2025-01-01'
RETURNING id, user_id, payload, created_at;
А теперь используем возвращённые строки как источник для вставки:
WITH moved AS (
DELETE FROM events
WHERE created_at < DATE '2025-01-01'
RETURNING id, user_id, payload, created_at
)
INSERT INTO events_archive (
id, user_id, payload, created_at
)
SELECT id, user_id, payload, created_at
FROM moved;
Всё выполняется одним оператором SQL. Если вставка в архив завершится ошибкой, удаление тоже откатится.
При этом можно преобразовать данные перед архивированием:
WITH moved AS (
DELETE FROM events
WHERE created_at < DATE '2025-01-01'
RETURNING id, payload, created_at
)
INSERT INTO events_archive (id, payload, archived_at)
SELECT id, payload, now()
FROM moved;
DELETE ... RETURNING внутри WITH позволяет переносить строки между таблицами одним атомарным запросом, без отдельного чтения и передачи данных через приложение.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤7👍6
В этой статье:
• Узнаете, почему EXPLAIN не всегда помогает понять причины медленного выполнения SQL-запросов;• Разберёте, как pg_query_state позволяет отслеживать выполнение запросов в Apache Cloudberry в реальном времени;• Посмотрите, как архитектура с Go-агентами и сервисом YAGPCC помогает собирать метрики с множества узлов без перегрузки координатора.🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9🤝7🔥4
Вот отсортированная база с тонной материала (постепенно пополняется):
(363 видео, 87 книги) — Python
(117 видео, 53 книги) — ВАЙБКОД
(174 видео, 91 книги) — DevOps
(415 видео, 68 книги) — Frontend
(137 видео, 93 книги) — DS/ML
(143 видео, 33 книги) — ИБ/Хакинг
(352 видео, 89 книги) — С/С++/C
(343 видео, 87 книги) — Java/QA
(176 видео, 32 книги) — Git/Linux
(167 видео, 53 книги) — PHP/1С
(227 видео, 83 книги) — SQL/БД
(114 видео, 77 книги) — Сисадмин
(107 видео, 43 книги) — BA/SA
(181 видео, 32 книги) — Go/Rust
(167 видео, 43 книги) — Kotlin/Swift
(112 видео, 24 книги) — Flutter
(113 видео, 82 книги) — GameDev
(183 видео, 37 книги) — Дизайн
(136 видео, 33 книги) — PM/HR
Скачивать ничего не нужно — все выложили в Telegram
Please open Telegram to view this post
VIEW IN TELEGRAM
Почему перенос условия из ON в WHERE меняет семантику LEFT JOIN
При использовании
Рассмотрим запрос, который должен возвращать всех пользователей и количество их завершённых заказов:
Этот запрос исключает пользователей без завершённых заказов. Предикат
Для сохранения всех пользователей ограничение на статус необходимо включить в условие соединения:
Теперь пользователь без завершённых заказов остаётся в результате с количеством
В PostgreSQL аналогичную задачу можно решить через агрегатный
Различие между этими вариантами становится существенным при вычислении нескольких агрегатов.
Есть и важное следствие для оптимизатора PostgreSQL. Если условие в
Проверить фактический план выполнения можно через
В плане может появиться
🔥 Перенос предиката между
➡️ SQL Ready | #практика
При использовании
LEFT JOIN расположение предиката определяет не только состав результата, но и возможность сохранить строки левой таблицы без соответствий. Предикаты в ON участвуют в поиске совпадений, тогда как WHERE фильтрует результат соединения.Рассмотрим запрос, который должен возвращать всех пользователей и количество их завершённых заказов:
SELECT
u.id,
COUNT(o.id) AS completed_orders
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
WHERE o.status = 'completed'
GROUP BY u.id;
Этот запрос исключает пользователей без завершённых заказов. Предикат
o.status = 'completed' является null-rejecting: он не может вернуть TRUE, когда o.status содержит NULL. Поэтому строки, дополненные NULL при внешнем соединении, отбрасываются.Для сохранения всех пользователей ограничение на статус необходимо включить в условие соединения:
SELECT
u.id,
COUNT(o.id) AS completed_orders
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
AND o.status = 'completed'
GROUP BY u.id;
Теперь пользователь без завершённых заказов остаётся в результате с количеством
0. Здесь принципиально использование COUNT(o.id): агрегат игнорирует NULL, тогда как COUNT(*) учитывает и строку, созданную внешним соединением при отсутствии совпадений.В PostgreSQL аналогичную задачу можно решить через агрегатный
FILTER, сохранив соединение со всеми заказами:SELECT
u.id,
COUNT(o.id) FILTER (
WHERE o.status = 'completed'
) AS completed_orders
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
GROUP BY u.id;
Различие между этими вариантами становится существенным при вычислении нескольких агрегатов.
FILTER позволяет применять независимые условия к разным агрегатам без повторного соединения таблиц:SELECT
u.id,
COUNT(o.id) FILTER (
WHERE o.status = 'completed'
) AS completed_orders,
COUNT(o.id) FILTER (
WHERE o.status = 'pending'
) AS pending_orders
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
GROUP BY u.id;
Есть и важное следствие для оптимизатора PostgreSQL. Если условие в
WHERE исключает все строки с NULL со стороны правой таблицы, внешнее соединение в некоторых случаях может быть преобразовано во внутреннее. Такое преобразование сохраняет семантику исходного запроса, но не исправляет ошибочно выбранную логику фильтрации.Проверить фактический план выполнения можно через
EXPLAIN:EXPLAIN (ANALYZE, BUFFERS)
SELECT
u.id,
COUNT(o.id)
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
WHERE o.status = 'completed'
GROUP BY u.id;
В плане может появиться
Hash Join вместо Hash Left Join или другой тип внутреннего соединения. Конкретный алгоритм зависит от статистики, индексов и оценок стоимости, поэтому наличие LEFT JOIN в sql не гарантирует сохранение внешнего соединения в физическом плане.ON и WHERE при внешнем соединении — семантическое преобразование, а не просто изменение записи sql. Null-rejecting предикаты могут устранять строки без совпадений и создавать условия для упрощения LEFT JOIN до INNER JOIN оптимизатором.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11❤8👍5
Например, Two Pointers помогает эффективно работать с массивами, Sliding Window — находить подмассивы по заданным условиям, а Dynamic Programming — решать сложные задачи через повторное использование результатов подзадач.
На картинке — 16 популярных алгоритмических паттернов и структур данных, которые пригодятся на технических собеседованиях.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤5🤝5🔥2
Требуются парни и девушки в возрасте 19–40 лет, желающие работать в сфере IT.
Опыт в программировании не нужен.
Завтра запускаем бесплатный онлайн-интенсив по Frontend-разработке, где будем показывать, как разрабатывать сайты и веб-приложения используя ИИ.
За 7 дней обучения без опыта ты:
1. Сделаешь реальный сайт сервиса доставки с нуля;
2. Добавишь JavaScript-логику, расчёты и трекинг;
3. Подключишь карты и маршрут доставки через API;
4. Превратишь сайт в Angular-приложение;
5. Подключишь backend и выложишь проект в продакшен;
6. Научишься использовать ChatGPT и Giga во Frontend-разработке;
7. Узнаешь 9 способов найти первый заказ на фрилансе даже без опыта.
А главное, ты увидишь, что разрабатывать сайты и приложения не так сложно, как кажется. И поймёшь, как тебе развиваться в этой профессии, чтобы уже через пару месяцев зарабатывать от 1000$ на вёрстке сайтов.
👉 Проскочить на интенсив бесплатно
🔥 С 2019 стабильно помогаем с обучением, практикой, зарабатывать на фрилансе и проходить собеседования.
Опыт в программировании не нужен.
Завтра запускаем бесплатный онлайн-интенсив по Frontend-разработке, где будем показывать, как разрабатывать сайты и веб-приложения используя ИИ.
За 7 дней обучения без опыта ты:
1. Сделаешь реальный сайт сервиса доставки с нуля;
2. Добавишь JavaScript-логику, расчёты и трекинг;
3. Подключишь карты и маршрут доставки через API;
4. Превратишь сайт в Angular-приложение;
5. Подключишь backend и выложишь проект в продакшен;
6. Научишься использовать ChatGPT и Giga во Frontend-разработке;
7. Узнаешь 9 способов найти первый заказ на фрилансе даже без опыта.
А главное, ты увидишь, что разрабатывать сайты и приложения не так сложно, как кажется. И поймёшь, как тебе развиваться в этой профессии, чтобы уже через пару месяцев зарабатывать от 1000$ на вёрстке сайтов.
👉 Проскочить на интенсив бесплатно
🔥 С 2019 стабильно помогаем с обучением, практикой, зарабатывать на фрилансе и проходить собеседования.
👎7
Ускоряйте массовую загрузку через FREEZE!
При загрузке данных в новую таблицу PostgreSQL может сразу пометить строки как замороженные. Для этого у
Опция пригодится и при повторной полной загрузке таблицы:
🔥 Используйте
➡️ SQL Ready | #совет
При загрузке данных в новую таблицу PostgreSQL может сразу пометить строки как замороженные. Для этого у
COPY есть малоизвестная опция FREEZE.BEGIN;
CREATE TABLE events_import (
id bigint,
payload jsonb
);
COPY events_import
FROM '/data/events.csv'
WITH (FORMAT csv, FREEZE true);
COMMIT;
FREEZE позволяет избежать последующей работы по заморозке загруженных строк. Но есть условие: таблица должна быть создана или очищена через TRUNCATE в текущей подоперации транзакции.Опция пригодится и при повторной полной загрузке таблицы:
BEGIN;
TRUNCATE events_import;
COPY events_import
FROM '/data/events.csv'
WITH (FORMAT csv, FREEZE true);
COMMIT;
FREEZE не отключает обычные проверки ограничений и не гарантирует ускорения самого импорта. Его преимущество — уменьшение будущей работы VACUUM по заморозке строк.COPY FREEZE при полной загрузке новых или очищенных таблиц, чтобы сократить последующую работу по обслуживанию данных.Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥6❤3🤝3