Булевы флаги через ::int: один трюк, шесть применений
Всем привет! На связи Александр Грудинин, ментор профессии «Аналитик данных» 👋🏻
В учебниках мы часто видим, как условную логику реализуют через CASE WHEN ... THEN 1 ELSE 0 END. В боевых запросах то же пишут короче: условие в скобках и приведение к числу. В PostgreSQL любое сравнение это булево значение, а TRUE::int = 1, FALSE::int = 0:
(status = 'active')::int AS is_active,
((age > 18) AND (verified = true))::int AS is_adult_verified
Это читается как бизнес-правило. Но короткая запись — это только верхушка айсберга. Настоящая сила в том, что флаг — это число, а числа можно суммировать, усреднять, брать максимум и умножать. Каждая операция даёт отдельный приём.
💡 Флаг существования после LEFT JOIN
После LEFT JOIN непарные строки получают NULL в колонках правой таблицы. Проверка на NULL, свёрнутая во флаг, отвечает на вопрос «есть ли связанная запись»:
(o.order_id IS NOT NULL)::int AS has_order
Дальше has_order работает и как фильтр, и как метрика: «сколько клиентов с заказом» — просто SUM(has_order).
💡 SUM(флаг) — счётчик, AVG(флаг) — доля
Раз флаг — это 0 или 1, агрегаты читаются напрямую:
SUM(is_active) -- сколько активных строк
AVG(is_active) -- доля активных (готовый процент)
COUNT(*) - SUM(has_order) -- сколько клиентов без заказа
Один проход по таблице вместо трёх запросов с разными WHERE.
💡 MAX(флаг) по группе — «случалось ли хоть раз»
Если внутри группы флаг хоть в одной строке равен 1, то MAX по группе тоже даст 1. То есть MAX(флаг) отвечает на вопрос «было ли такое хотя бы раз»:
SELECT
user_id,
MAX((amount > 1000)::int) AS had_big_purchase
FROM orders
GROUP BY user_id
Читается так: «у пользователя был хотя бы один заказ дороже 1000». Без трюка пришлось бы писать самоджойн или коррелированный подзапрос.
Симметрично работает MIN(флаг) = 1 — «условие выполнилось во всех строках группы».
Ставьте 🔥, если было полезно!
📈 Симулейтив | 📱 ВК | 📱 YouTube | 📱 Канал о DS
Всем привет! На связи Александр Грудинин, ментор профессии «Аналитик данных» 👋🏻
В учебниках мы часто видим, как условную логику реализуют через CASE WHEN ... THEN 1 ELSE 0 END. В боевых запросах то же пишут короче: условие в скобках и приведение к числу. В PostgreSQL любое сравнение это булево значение, а TRUE::int = 1, FALSE::int = 0:
(status = 'active')::int AS is_active,
((age > 18) AND (verified = true))::int AS is_adult_verified
Это читается как бизнес-правило. Но короткая запись — это только верхушка айсберга. Настоящая сила в том, что флаг — это число, а числа можно суммировать, усреднять, брать максимум и умножать. Каждая операция даёт отдельный приём.
💡 Флаг существования после LEFT JOIN
После LEFT JOIN непарные строки получают NULL в колонках правой таблицы. Проверка на NULL, свёрнутая во флаг, отвечает на вопрос «есть ли связанная запись»:
(o.order_id IS NOT NULL)::int AS has_order
Дальше has_order работает и как фильтр, и как метрика: «сколько клиентов с заказом» — просто SUM(has_order).
💡 SUM(флаг) — счётчик, AVG(флаг) — доля
Раз флаг — это 0 или 1, агрегаты читаются напрямую:
SUM(is_active) -- сколько активных строк
AVG(is_active) -- доля активных (готовый процент)
COUNT(*) - SUM(has_order) -- сколько клиентов без заказа
Один проход по таблице вместо трёх запросов с разными WHERE.
💡 MAX(флаг) по группе — «случалось ли хоть раз»
Если внутри группы флаг хоть в одной строке равен 1, то MAX по группе тоже даст 1. То есть MAX(флаг) отвечает на вопрос «было ли такое хотя бы раз»:
SELECT
user_id,
MAX((amount > 1000)::int) AS had_big_purchase
FROM orders
GROUP BY user_id
Читается так: «у пользователя был хотя бы один заказ дороже 1000». Без трюка пришлось бы писать самоджойн или коррелированный подзапрос.
Симметрично работает MIN(флаг) = 1 — «условие выполнилось во всех строках группы».
Ставьте 🔥, если было полезно!
📈 Симулейтив | 📱 ВК | 📱 YouTube | 📱 Канал о DS