Запросы - Синтаксис (Task 1 and 2)
This commit is contained in:
@@ -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 - нет в классическом понимании, а скорее в итеративном смысле.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user