230 lines
6.7 KiB
SQL
230 lines
6.7 KiB
SQL
# Задачи на отработку:
|
||
|
||
### **Задача 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?
|
||
МНОГОУРОВНЕВОСТЬ ЕСТЬ, А РЕКУРСИВНОСТИ НЕТ. |