Files
homework/dmezentsev/postgresql/homework/Functions.sql
T
2026-05-19 10:39:11 +03:00

144 lines
7.6 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Задача 1. Давность регистрации пользователей
SELECT name,
CAST(created_at AS DATE) AS created_date,
CURRENT_DATE - created_at::DATE AS days_since_registration,
is_active
FROM dmezentsev.users
WHERE CURRENT_DATE - created_at::DATE > 180
ORDER BY days_since_registration DESC;
/* - Как бы ты использовал такое поле в реальном продукте
(что можно делать с очень «старыми» пользователями)?
В реальности можно давать какие-то бонусы самым лояльным клиентам. Ну или
наоборот, удалить их, если зарегистрированы давно, а активности никакой
- Почему удобнее сразу вычитать created_at::date, а не created_at как timestamp?
Если вычитать ::date, то получается число, удобно сравнивать, применять при
фильтрации, в арифметических выражениях. Если timestamp, то интервал
*/
-- Задача 2. Нормализация email и доменов
SELECT name,
LOWER(email) AS email_clean,
SUBSTRING(LOWER(email) FROM POSITION('@' IN email) + 1) AS domain
FROM dmezentsev.users
WHERE email IS NOT NULL
ORDER BY domain, name;
/* - Зачем в реальных системах приводят email к нижнему регистру и выделяют домен отдельно?
email - адреса приводят к нижнему регистру, потому что в БД один и тот же
почтовый ящик в разном регистре будет считаться двумя почтовыми ящиками, что
приведет к дублям. Так же если пользователь введет свой почтовый ящик не в таком
регистре, в котором ящик сохранен в БД, то он не сможет залогиниться
Домен выделяют отдельно для анализа, маркетинга. Так же ради безопасности,
чтобы блочить подозрительные домены
*/
-- Задача 3. Сегменты по возрасту
SELECT name,
age,
CASE
WHEN age < 25 THEN 'young'
WHEN age BETWEEN 25 AND 35 THEN 'adult'
ELSE 'senior'
END AS age_group
FROM dmezentsev.users
ORDER BY age;
/* - Почему удобнее держать логику сегментации в SQL (CASE), а не только в коде приложения?
Вот тут точно не знаю, но мне кажется, что сегментация в SQL вернет результат.
А если писать это в коде приложения, то выгрузка всех строк выльется в большой
объем данных, которые нужно будет еще и обработать
- Что произойдёт, если в CASE забыть ветку ELSE 
(что получат пользователи, не попавшие ни в одно условие)?
Если забыть ELSE, то пользователи, которые не попадут ни под одно из условий,
получат NULL
*/
-- Задача 4. «Горячие» пользователи по дате и активности
SELECT
name,
created_at::DATE AS created_at_date,
CURRENT_DATE - created_at::DATE AS days_since_registration,
CASE
WHEN is_active AND (CURRENT_DATE - created_at::DATE <= 30) THEN 'hot'
ELSE 'regular'
END AS hot_flag
FROM dmezentsev.users
WHERE is_active AND (CURRENT_DATE - created_at::DATE <= 30);
/* - Чем отличается фильтрация по дате в WHERE от простого CASE с меткой 'hot',
но без фильтрации?
С фильтрацией в WHERE получим горячих с датой регистрации не больше 30 дней.
Если без WHERE, то получим всех пользователей (и горячих, и обычных)
- Какие типы рассылок/кампаний логично запускать только на «горячих»?
Предположу, что горячим можно рассылать специальные предложения, чтобы
дополнительно завлечь. Так же можно сделать рассылку по онбордингу, чтобы
легче вкатиться в фичи сервиса
*/
-- Задача 5. Качество данных по email
SELECT COUNT(*) AS total_users,
COUNT(email) AS with_email,
COUNT(*) FILTER (WHERE email IS NULL) AS without_email,
COUNT(*) FILTER (WHERE email IS NULL)::NUMERIC
/ COUNT(*) * 100 AS without_email_percent
FROM dmezentsev.users;
/* - Почему для проверки «долей» и «заполненности» полей
лучше использовать агрегаты в SQL, а не просто «на глаз» смотреть на таблицу?
Агрегаты гораздо легче воспринимать на глаз, чем смотреть всю таблицу.
По сути, это уже готовый ответ на поставленный вопрос. Другое дело
пытаться понять по всем данным, что вообще происходит.
Особенно, если там миллионы строк.
- Какие действия по данным ты бы предложил продукту,
если доля пользователей без email слишком большая?
Если бы доля юзеров, не заполняюших email, оказалась слишком большой, то я
бы советовал сделать ввод email обязательным, ну или использовать email как
логин. Как вариант, предложить какой-то бонус типа промокода
*/
-- Задача 6. «Стаж» пользователя и его группа
SELECT name,
CASE
WHEN CURRENT_DATE - created_AT::DATE <= 30 THEN 'new'
WHEN CURRENT_DATE - created_AT::DATE BETWEEN 31 AND 180 THEN 'middle'
ELSE 'old'
END AS tenure_group,
CURRENT_DATE - created_AT::DATE AS days_since_registration,
is_active
FROM dmezentsev.users
ORDER BY tenure_group,
days_since_registration;
/* Чем сегментация по «стажу» отличается по смыслу от сегментации по возрасту?
Стаж - это время с момента регистрации. Думаю, такая сегментация необходима для того, чтобы
по этим сегментам проводить какую-то свою аналитику, отличную для каждого из них.
Например: стаж - аналитика лояльности, возраст - аналитика платежеспособности
- Если пересчитывать tenure_group прямо в SQL каждый день,
какие плюсы и минусы по сравнению с хранением статического поля segment?
Плюс перерасчета стажа каждый день - это актуальность данных, которые потом
будут использоваться аналитиками
*/