# Задачи на отработку: ### **Задача 1.** Есть таблица `users`: | user_id | name | age | country | is_active | | --- | --- | --- | --- | --- | | 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 | CREATE TABLE users ( user_id UInt64, name String, age UInt32, country String, is_active UInt32 ) ENGINE = MergeTree() ORDER BY (age, country); 1. Получи 10 самых старших **активных** пользователей. SELECT user_id, name, age FROM users WHERE is_active = 1 ORDER BY age DESC LIMIT 10; 2. Выведи пользователей из `country = 'RU'`, отсортированных по имени. SELECT user_id, name FROM users WHERE country = 'RU' ORDER BY name; 3. Что произойдёт, если написать `LIMIT 10` **без `ORDER BY`**? В таком случае CH покажет 10 произвольных неотсортированных строк 4. Посчитай количество пользователей по странам. SELECT country, COUNT(*) FROM users GROUP BY country; 5. Для каждой страны выведи минимальный и максимальный возраст. SELECT country, MIN(age), MAX(age) FROM users GROUP BY country; 6. Отсортируй страны по убыванию количества пользователей. SELECT country, COUNT(*) FROM users GROUP BY country ORDER BY COUNT(*) DESC; 📌 Дополнительно: - Используй `count()`, `min()`, `max()`, `sum()` - Попробуй `uniqExact(country)` — что он делает? uniqExact выводит количество уникальных значений, это тоже самое что и DISTINCT ### **Задача 2.** Есть таблица `events`: | user_id | event_time | event_type | | --- | --- | --- | | 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 | CREATE TABLE events ( user_id UInt64, event_type String, event_time DateTime64(3) ) ENGINE = MergeTree() ORDER BY (event_time, user_id); INSERT INTO dmedvedev.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, COUNT() OVER (PARTITION BY user_id ORDER BY user_id) FROM events; 2. Сделай аналог ранжирования событий внутри пользователя: `row_number() OVER (PARTITION BY user_id ORDER BY event_time)` SELECT user_id, COUNT(*) OVER (PARTITION BY user_id ORDER BY event_time) FROM events; 3. Что будет, если ты явно задашь `ROWS BETWEEN`? Поддерживается ли? Посчитается, поддерживается. SELECT user_id, COUNT(*) OVER ( PARTITION BY user_id ORDER BY event_time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM events; 4. Сделай `WITH recent_events AS (...)` — все события за последние 24 часа. SELECT user_id, event_time FROM events WHERE event_time <= NOW() - INTERVAL 24 HOUR; 5. Используй CTE, чтобы посчитать топ-5 пользователей по числу этих событий. WITH recent_events AS ( SELECT user_id, event_type, event_time FROM events WHERE event_time >= NOW() - INTERVAL 24 HOUR ) SELECT user_id, COUNT(*) FROM recent_events GROUP BY user_id ORDER BY COUNT(*) DESC LIMIT 5; 6. Добавь второй `WITH` — для маппинга `event_type → category` и используй его в основном запросе. WITH recent_events AS ( SELECT user_id, event_type, event_time FROM events WHERE event_time >= NOW() - INTERVAL 24 HOUR ), top_users AS( SELECT user_id, COUNT(*) FROM recent_events GROUP BY user_id ORDER BY COUNT(*) DESC LIMIT 5 ) SELECT user_id, CASE WHEN event_type IN ('click', 'view') THEN 'interaction' WHEN event_type IN ('purchase') THEN 'conversion' ELSE 'unknown' END AS category FROM recent_events re INNER JOIN top_users tu ON re.user_id = tu.user_id; 📌 Вопрос: поддерживает ли ClickHouse **многоуровневые** или **рекурсивные** CTE? МНОГОУРОВНЕВОСТЬ ЕСТЬ, А РЕКУРСИВНОСТИ НЕТ.