diff --git a/dsolovianov/clickhouse/Homework/Запросы - Синтаксис.sql b/dsolovianov/clickhouse/Homework/Запросы - Синтаксис.sql new file mode 100644 index 0000000..47d7629 --- /dev/null +++ b/dsolovianov/clickhouse/Homework/Запросы - Синтаксис.sql @@ -0,0 +1,224 @@ +/* Запросы - Синтаксис*/ + +--! Задача 1 !-- + +DROP TABLE IF EXISTS users ON CLUSTER clickhouse_cluster; + +CREATE TABLE users +ON CLUSTER clickhouse_cluster +( + user_id UInt32, + name String, + age UInt8, + country String, + is_active UInt8 +) ENGINE = MergeTree() +ORDER BY user_id; + +INSERT INTO users VALUES +(1, 'Ivan', 30, 'RU', 1), +(2, 'Anna', 25, 'RU', 1), +(3, 'Petr', 45, 'RU', 0), +(4, 'Olga', 35, 'RU', 1), +(5, 'John', 55, 'US', 1), +(6, 'Alice', 42, 'US', 0), +(7, 'Tom', 38, 'US', 1), +(8, 'Lucas', 28, 'BR', 1), +(9, 'Maria', 60, 'BR', 1), +(10, 'João', 27, 'BR', 0), +(11, 'Kenji', 33, 'JP', 1), +(12, 'Yuki', 29, 'JP', 0), +(13, 'Chen', 40, 'CN', 1), +(14, 'Li', 48, 'CN', 1), +(15, 'Fatima', 31, 'AE', 1), +(16, 'Ahmed', 36, 'AE', 1), +(17, 'George', 24, 'US', 1), +(18, 'Nina', 34, 'RU', 1), +(19, 'Max', 50, 'DE', 1), +(20, 'Sophie', 22, 'DE', 0); + +--Получи 10 самых старших активных пользователей. +SELECT + user_id, + name, + age, + is_active +FROM users +WHERE is_active = true +ORDER BY age DESC +LIMIT 10; + +--Выведи пользователей из country = 'RU', отсортированных по имени. +SELECT + user_id, + name, + country +FROM users +WHERE country = 'RU' +ORDER BY name; + +--Что произойдёт, если написать LIMIT 10 без ORDER BY? Просто выведет 10 случайных активных прользователей без какой либо сортировки. +SELECT + user_id, + name, + age +FROM users +WHERE is_active = true +LIMIT 10; + +--Посчитай количество пользователей по странам. +SELECT + country, + COUNT(*) as user_country +FROM users +GROUP BY country; + +--Для каждой страны выведи минимальный и максимальный возраст. +SELECT + country, + MIN(age) as min_age, + MAX(age) as max_age +FROM users +GROUP BY country +ORDER BY country; + +--Отсортируй страны по убыванию количества пользователей. +SELECT + country, + COUNT(*) as user_country +FROM users +GROUP BY country +ORDER BY user_country DESC; + +--! Задача 2 !-- + +DROP TABLE IF EXISTS dsolovianov.events ON CLUSTER clickhouse_cluster SYNC; + +CREATE TABLE dsolovianov.events ON CLUSTER clickhouse_cluster +( + user_id UInt32, + event_time DateTime, + event_type String +) +ENGINE = ReplicatedMergeTree( + '/clickhouse/tables/{shard}/dsolovianov/events_v2', + '{replica}' +) +ORDER BY user_id; + +INSERT INTO dsolovianov.events (user_id, event_time, event_type) VALUES +(1, '2025-07-17 09:00:00', 'click'), +(1, '2025-07-17 09:05:00', 'view'), +(1, '2025-07-17 09:10:00', 'purchase'), +(2, '2025-07-17 10:00:00', 'click'), +(2, '2025-07-17 10:05:00', 'click'), +(2, '2025-07-17 11:00:00', 'view'), +(3, '2025-07-16 12:00:00', 'view'), +(3, '2025-07-16 12:30:00', 'click'), +(3, '2025-07-17 08:00:00', 'purchase'), +(4, '2025-07-17 13:00:00', 'click'), +(4, '2025-07-17 14:00:00', 'view'), +(4, '2025-07-17 15:00:00', 'view'), +(5, '2025-07-16 20:00:00', 'view'), +(5, '2025-07-17 01:00:00', 'click'), +(5, '2025-07-17 06:00:00', 'purchase'), +(6, '2025-07-17 07:30:00', 'view'), +(6, '2025-07-17 08:45:00', 'click'), +(7, '2025-07-16 23:59:59', 'click'), +(7, '2025-07-17 00:01:00', 'purchase'), +(7, '2025-07-17 10:10:00', 'view'); + +--1. Добавь колонку с кумулятивным количеством событий по `user_id` (используй `count() OVER ...`). +SELECT + user_id, + event_time, + event_type, + COUNT(*) OVER (PARTITION BY user_id ORDER BY event_time) AS cumulative_events +FROM dsolovianov.events +ORDER BY user_id, event_time; + +--2. Сделай аналог ранжирования событий внутри пользователя: `row_number() OVER (PARTITION BY user_id ORDER BY event_time)` +SELECT + user_id, + event_time, + event_type, + ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_time) AS event_rank +FROM dsolovianov.events +ORDER BY user_id, event_rank; + +--3. Что будет, если ты явно задашь `ROWS BETWEEN`? Поддерживается ли? +--Да, `ROWS BETWEEN` поддерживается: +SELECT + user_id, + event_time, + event_type, + -- кумулятивное окно (все предыдущие строки) + COUNT(*) OVER (PARTITION BY user_id ORDER BY event_time + ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_events, + -- скользящее окно: текущая + 2 предыдущих события + COUNT(*) OVER (PARTITION BY user_id ORDER BY event_time + ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS last_3_events, + -- окно: предыдущая + текущая + следующая + COUNT(*) OVER (PARTITION BY user_id ORDER BY event_time + ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS prev_curr_next +FROM dsolovianov.events +ORDER BY user_id, event_time; + +--4. Сделай `WITH recent_events AS (...)` — все события за последние 24 часа. +WITH recent_events AS ( + SELECT * + FROM dsolovianov.events + WHERE event_time >= '2025-07-16 15:00:00' +) +SELECT * FROM recent_events +ORDER BY event_time DESC; + +--5. Используй CTE, чтобы посчитать топ-5 пользователей по числу этих событий. +WITH recent_events AS ( + SELECT * + FROM dsolovianov.events + WHERE event_time >= '2025-07-16 15:00:00' +) +SELECT + user_id, + COUNT(*) AS event_count +FROM recent_events +GROUP BY user_id +ORDER BY event_count DESC +LIMIT 5; + +--6. Добавь второй `WITH` — для маппинга `event_type → category` и используй его в основном запросе. +WITH +event_categories AS ( + SELECT + event_type, + CASE + WHEN event_type = 'click' THEN 'engagement' + WHEN event_type = 'view' THEN 'engagement' + WHEN event_type = 'purchase' THEN 'conversion' + ELSE 'other' + END AS category + FROM (SELECT DISTINCT event_type FROM dsolovianov.events) +), +recent_events AS ( + SELECT * + FROM dsolovianov.events + WHERE event_time >= '2025-07-16 15:00:00' +) +SELECT + re.user_id, + re.event_time, + re.event_type, + ec.category, + ROW_NUMBER() OVER (PARTITION BY re.user_id ORDER BY re.event_time) AS event_rank, + COUNT(*) OVER (PARTITION BY re.user_id ORDER BY re.event_time) AS cumulative_events +FROM recent_events re +LEFT JOIN event_categories ec ON re.event_type = ec.event_type +ORDER BY re.user_id, re.event_time; + +/* +Вопрос: поддерживает ли ClickHouse многоуровневые или рекурсивные CTE? +многоуровневые CTE - да +рекурсивные CTE - нет в классическом понимании, а скорее в итеративном смысле. +*/ +