add tasks with function, string, logic
This commit is contained in:
@@ -0,0 +1,109 @@
|
|||||||
|
--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?
|
||||||
|
Можно будет понимать в динамике сколько старичков и сколько молодых, можно будет видеть приросты пользователей за каждый день.
|
||||||
|
*/
|
||||||
Reference in New Issue
Block a user