--task 1 --Задача 1. Давность регистрации пользователей SELECT name, created_at::date AS created_date, CURRENT_DATE - created_at::date AS date_since_registration FROM users u WHERE CURRENT_DATE - created_at::date > 180 ORDER BY date_since_registration DESC /*Как бы ты использовал такое поле в реальном продукте (что можно делать с очень «старыми» пользователями)? В зависимости от их активности можно предложить те или иные плюшки. Почему удобнее сразу вычитать created_at::date, а не created_at как timestamp? Потому что CURRENT_DATE - это просто текущая дата без учета времени */ --task 2 --Задача 2. Нормализация email и доменов SELECT name, LOWER(email) AS email_clean, substring(LOWER(email) FROM POSITION('@' IN email) +1) AS domain FROM users WHERE email IS NOT NULL ORDER BY domain, name /* Зачем в реальных системах приводят email к нижнему регистру и выделяют домен отдельно? Возможно потому что люди могут писать с разным регистром, и если бы это учитывалось, то одинаковые почтовые ящики с разными регистрами были бы совершенно разными. А системе не нужны дубликаты с разными регистрами. Что будет, если по ошибке не отфильтровать email IS NOT NULL (что получишь в domain)? Получу NULL,человек не заполнил ячейку имэйла при регистрации. */ --task 3 --Задача 3. Сегменты по возрасту SELECT name, age, CASE WHEN age < 25 THEN 'young' WHEN age BETWEEN 25 and 35 THEN 'adult' WHEN age > 35 THEN 'senior' END AS age_group FROM users ORDER BY age /* Почему удобнее держать логику сегментации в SQL (CASE), а не только в коде приложения? Возможно, Так проще работать с данными Что произойдёт, если в CASE забыть ветку ELSE (что получат пользователи, не попавшие ни в одно условие)? У них появятся значения NULL */ --task 4 --Задача 4. «Горячие» пользователи по дате и активности SELECT name, created_at::date AS created_date, CURRENT_DATE - created_at::date AS days_since_registration, CASE WHEN (is_active IS TRUE OR CURRENT_DATE - created_at::date <= 30) THEN 'hot' ELSE 'regular' END AS hot_flag FROM users WHERE (is_active IS TRUE OR CURRENT_DATE - created_at::date <= 30) /*Чем отличается фильтрация по дате в WHERE от простого CASE с меткой 'hot', но без фильтрации? Последовательностью выполнения, различными функциями (в одном фильтрация идет, в другом просто присваивание определенному условию наименования в дополнительном столбце) Какие типы рассылок/кампаний логично запускать только на «горячих»? */ --task 5 --Задача 5. Качество данных по email SELECT COUNT(*) AS total_users, COUNT(email) AS with_email, COUNT(*) - COUNT(email) AS without_email, (COUNT(*) - COUNT(email)) * 100.0 / COUNT(*) AS dolya FROM users /*Почему для проверки «долей» и «заполненности» полей лучше использовать агрегаты в SQL, а не просто «на глаз» смотреть на таблицу? То ли я туп, то ли вопрос с подковыркой для меня. Если значений может быть миллион, то как еще это делать, если не через агрегаты? Какие действия по данным ты бы предложил продукту, если доля пользователей без email слишком большая? Как минимум при регистрации сделать поле "имэйл" обязательным для заполнения. */ --task 6 --Задача 6. «Стаж» пользователя и его группа SELECT name, CURRENT_DATE - created_at::date AS says_since_registration, CASE WHEN CURRENT_DATE - created_at::date <= 30 THEN 'new' WHEN CURRENT_DATE - created_at::date > 180 THEN 'old' ELSE 'middle' END AS tenure_group, is_active FROM users ORDER BY tenure_group, says_since_registration /* Чем сегментация по «стажу» отличается по смыслу от сегментации по возрасту? Если пересчитывать tenure_group прямо в SQL каждый день, какие плюсы и минусы по сравнению с хранением статического поля segment? Можно будет понимать в динамике сколько старичков и сколько молодых, можно будет видеть приросты пользователей за каждый день. */