225 lines
6.8 KiB
SQL
225 lines
6.8 KiB
SQL
/* Запросы - Синтаксис*/
|
|
|
|
--! Задача 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 - нет в классическом понимании, а скорее в итеративном смысле.
|
|
*/
|
|
|