task up to arrays
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
--task 1
|
||||
select
|
||||
user_id,
|
||||
indexOf(tags, 'promo') as promo_index,
|
||||
arrayJoin(tags)
|
||||
from events
|
||||
where has(tags, 'promo')
|
||||
|
||||
-- task 2
|
||||
select
|
||||
user_id,
|
||||
scores['math'] as math_score,
|
||||
mapValues(scores) as all_values
|
||||
from metrics
|
||||
|
||||
-- task 3
|
||||
select
|
||||
name,
|
||||
contact.type as contact_type,
|
||||
contact.value as contact_value
|
||||
from users_nested
|
||||
array join contacts as contact
|
||||
where contact.type = 'email'
|
||||
@@ -0,0 +1,61 @@
|
||||
-- task 1
|
||||
CREATE TABLE raw_data (
|
||||
user_id String,
|
||||
balance String,
|
||||
created_at String
|
||||
) ENGINE = MergeTree ORDER BY tuple();
|
||||
|
||||
select
|
||||
user_id,
|
||||
toDecimal64OrNull(balance, 2) as balance,
|
||||
toTimeDate64OrNull(created_at, 3) as created_at
|
||||
from raw_data
|
||||
where
|
||||
toDecimal64OrNull(balance, 2) is not null and
|
||||
toTimeDate64OrNull(created_at, 3) is not null
|
||||
|
||||
-- task 2 (failed)
|
||||
CREATE TABLE events (
|
||||
event_id String,
|
||||
event_date String, -- форматы: "2023-01-01", "01.02.2023", "invalid"
|
||||
event_time String -- форматы: "12:30:45", "25:99:99"
|
||||
);
|
||||
|
||||
select
|
||||
event_id,
|
||||
toStartOfHour(toDateTimeOrNull(concatWithSeparator(' ', events_date, events_time)))
|
||||
from events
|
||||
where
|
||||
toDateOrNull(event_date) is not null and toTimeOrNull(event_time) is not null
|
||||
|
||||
-- task 3
|
||||
CREATE TABLE user_activity (
|
||||
user_id UInt32,
|
||||
actions String -- JSON: ["login", "purchase", "logout"]
|
||||
);
|
||||
SELECT
|
||||
user_id,
|
||||
actions_arr,
|
||||
length(actions_arr) AS actions_count
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
user_id,
|
||||
JSONExtract(actions, 'Array(String)') AS actions_arr
|
||||
FROM user_activity
|
||||
)
|
||||
WHERE has(actions_arr, 'purchase');
|
||||
|
||||
-- task 4
|
||||
CREATE TABLE sensor_data (
|
||||
sensor_id UInt32,
|
||||
value Float64,
|
||||
status Enum('ok' = 1, 'error' = 2)
|
||||
);
|
||||
SELECT
|
||||
toString(status) as status,
|
||||
avg(value) as avg_value
|
||||
from sensor_data
|
||||
where
|
||||
toDecimal64OrNull(value, 2) is not null
|
||||
group by status
|
||||
@@ -0,0 +1,103 @@
|
||||
--task 1
|
||||
create table mdrozdov.products (
|
||||
product_id Int,
|
||||
name String
|
||||
)
|
||||
engine = MergeTree
|
||||
order by product_id
|
||||
|
||||
insert into mdrozdov.products values
|
||||
(101, 'iPhone 14'),
|
||||
(102, 'Galaxy S22'),
|
||||
(103, 'Pixel 7')
|
||||
|
||||
create table mdrozdov.prices (
|
||||
product_id Int,
|
||||
price Int,
|
||||
region String
|
||||
)
|
||||
engine = MergeTree
|
||||
order by product_id
|
||||
|
||||
insert into mdrozdov.prices values
|
||||
(101, 999, 'US'),
|
||||
(101, 1049, 'EU'),
|
||||
(102, 850, 'US'),
|
||||
(102, 899, 'CA'),
|
||||
(103, 799, 'JP')
|
||||
|
||||
-- 1)
|
||||
select
|
||||
product_id,
|
||||
name,
|
||||
price,
|
||||
region
|
||||
from mdrozdov.products
|
||||
any left join mdrozdov.prices
|
||||
on mdrozdov.products.product_id = mdrozdov.prices.product_id
|
||||
|
||||
-- 2)
|
||||
create table mdrozdov.ticks
|
||||
ON CLUSTER clickhouse_cluster (
|
||||
time DateTime,
|
||||
symbol String,
|
||||
price Decimal(10, 2)
|
||||
)
|
||||
engine = ReplicatedMergeTree(
|
||||
'/clickhouse/tables/{shard}/mdrozdov/ticks',
|
||||
'{replica}'
|
||||
)
|
||||
order by (time, symbol)
|
||||
|
||||
insert into mdrozdov.ticks values
|
||||
('2025-07-17 10:00:00', 'AAPL', 190.5),
|
||||
('2025-07-17 10:01:00', 'AAPL', 191.2),
|
||||
('2025-07-17 10:02:30', 'AAPL', 192.0),
|
||||
('2025-07-17 10:05:00', 'GOOG', 2850.0)
|
||||
|
||||
create table mdrozdov.orders
|
||||
ON CLUSTER clickhouse_cluster (
|
||||
time DateTime,
|
||||
symbol String,
|
||||
size Int
|
||||
)
|
||||
engine = ReplicatedMergeTree(
|
||||
'/clickhouse/tables/{shard}/mdrozdov/orders',
|
||||
'{replica}'
|
||||
)
|
||||
order by size
|
||||
|
||||
insert into mdrozdov.orders values
|
||||
('2025-07-17 10:00:30', 'AAPL', 50),
|
||||
('2025-07-17 10:02:00', 'AAPL', 75),
|
||||
('2025-07-17 10:03:00', 'AAPL', 20),
|
||||
('2025-07-17 10:04:00', 'GOOG', 15)
|
||||
|
||||
select
|
||||
o.time,
|
||||
o.symbol,
|
||||
t.price as last_price
|
||||
from mdrozdov.orders o
|
||||
asof join mdrozdov.ticks t
|
||||
on o.symbol = t.symbol and o.time >= t.time
|
||||
|
||||
-- task 3
|
||||
select
|
||||
user_id,
|
||||
name
|
||||
from users
|
||||
where user_id in (
|
||||
select user_id
|
||||
from payments
|
||||
where amount > 1000
|
||||
)
|
||||
|
||||
-- task 4
|
||||
select
|
||||
bl.user_id,
|
||||
u.name,
|
||||
bl.event_time,
|
||||
bl.event_type,
|
||||
from big_logs bl
|
||||
any left join users u
|
||||
using(user_id)
|
||||
@@ -0,0 +1,64 @@
|
||||
--page_views table
|
||||
create table page_views (
|
||||
user_id UInt64,
|
||||
url String,
|
||||
view_time DateTime
|
||||
)
|
||||
Engine = MergeTree
|
||||
Order by (user_id, view_time)
|
||||
Partition by toYYYYMM(view_time)
|
||||
|
||||
-- users table
|
||||
create table users(
|
||||
id UInt64,
|
||||
name String,
|
||||
updated_at DateTime
|
||||
)
|
||||
ENGINE = ReplacingMergeTree(updated_at)
|
||||
Order by id;
|
||||
|
||||
-- region_sales table
|
||||
create table region_sales(
|
||||
region String,
|
||||
date Date,
|
||||
sales UInt64
|
||||
)
|
||||
ENGINE = SummingMergeTree
|
||||
Partition by toYYYYMM(date)
|
||||
Order by (region, date)
|
||||
|
||||
insert into mdrozdov.region_sales (region, date, sales)
|
||||
values ('Russia', '2025-01-14', 30), ('Russia', '2025-01-16', 22), ('USA', '2025-01-14', 1400)
|
||||
OPTIMIZE TABLE mdrozdov.region_sales FINAL
|
||||
|
||||
-- user_metrics table
|
||||
create table mdrozdov.user_metrics (
|
||||
region String,
|
||||
avg_age_state AggregateFunction(avg, UInt8),
|
||||
active_users_state AggregateFunction(uniq, UInt64)
|
||||
)
|
||||
Engine = AggregatingMergeTree
|
||||
Order by region
|
||||
|
||||
INSERT INTO mdrozdov.user_metrics
|
||||
SELECT
|
||||
'Moscow' AS region,
|
||||
avgState(toUInt8(25)) AS avg_age_state,
|
||||
uniqState(toUInt64(100)) AS active_users_state
|
||||
UNION ALL
|
||||
SELECT
|
||||
'Moscow',
|
||||
avgState(toUInt8(30)),
|
||||
uniqState(toUInt64(50))
|
||||
UNION ALL
|
||||
SELECT
|
||||
'SPB',
|
||||
avgState(toUInt8(20)),
|
||||
uniqState(toUInt64(10));
|
||||
|
||||
SELECT
|
||||
region,
|
||||
avgMerge(avg_age_state) AS avg_age,
|
||||
uniqMerge(active_users_state) AS active_users
|
||||
FROM mdrozdov.user_metrics
|
||||
GROUP BY region
|
||||
@@ -0,0 +1,136 @@
|
||||
CREATE TABLE users (
|
||||
user_id Int,
|
||||
name String,
|
||||
age Int,
|
||||
country String,
|
||||
is_active bool
|
||||
)
|
||||
engine = MergeTree
|
||||
order by user_id
|
||||
|
||||
insert into mdrozdov.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)
|
||||
|
||||
--1. Получи 10 самых старших **активных** пользователей.
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
age,
|
||||
country,
|
||||
is_active
|
||||
from mdrozdov.users
|
||||
where is_active
|
||||
order by age desc
|
||||
limit 10
|
||||
--2. Выведи пользователей из `country = 'RU'`, отсортированных по имени.
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
age,
|
||||
country,
|
||||
is_active
|
||||
from mdrozdov.users
|
||||
where country = 'RU'
|
||||
order by name asc
|
||||
--3. Что произойдёт, если написать `LIMIT 10` **без `ORDER BY`**?
|
||||
-- ответ будет недетерминирован
|
||||
--4. Посчитай количество пользователей по странам.
|
||||
select
|
||||
country,
|
||||
count(user_id) as total_users
|
||||
from mdrozdov.users
|
||||
group by country
|
||||
--5. Для каждой страны выведи минимальный и максимальный возраст.
|
||||
select
|
||||
country,
|
||||
min(age) as min_user_age,
|
||||
max(age) as max_user_age
|
||||
from mdrozdov.users
|
||||
group by country
|
||||
--6. Отсортируй страны по убыванию количества пользователей.
|
||||
select
|
||||
country,
|
||||
count(user_id) as total_users
|
||||
from mdrozdov.users
|
||||
group by country
|
||||
order by total_users desc
|
||||
|
||||
-- task 2
|
||||
CREATE TABLE mdrozdov.events (
|
||||
user_id Int,
|
||||
event_time DateTime,
|
||||
event_type String --mb better enum but idc
|
||||
)
|
||||
engine = MergeTree
|
||||
order by user_id
|
||||
insert into events 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-2) Добавь колонку с кумулятивным количеством событий по user_id (используй count() OVER ...)
|
||||
select
|
||||
user_id,
|
||||
event_time,
|
||||
event_type,
|
||||
count(*) over (partition by user_id order by event_time) as total_click_exact_moment,
|
||||
row_number() over (partition by user_id order by event_time) as row_number
|
||||
from mdrozdov.events
|
||||
--3) да, поддерживается, но не обязательно для коммулятивного суммирования строк
|
||||
--4-6) Сделай WITH recent_events AS (...) — все события за последние 24 часа.
|
||||
with recent_events AS (
|
||||
select *
|
||||
from mdrozdov.events
|
||||
where event_time >= '2025-07-18'::DATE - interval '1 day'
|
||||
), category_list as (
|
||||
select 'click' as event_type, 'interaction' as category
|
||||
union all
|
||||
select 'view', 'interaction'
|
||||
union all
|
||||
select 'purchase', 'conversion'
|
||||
)
|
||||
select
|
||||
user_id,
|
||||
count(*) as total_events_last_24h,
|
||||
count(distinct cl.category) as uniq_categories
|
||||
from recent_events re
|
||||
left join category_list cl
|
||||
using(event_type)
|
||||
group by user_id
|
||||
order by total_events_last_24h desc, user_id asc
|
||||
limit 5
|
||||
@@ -0,0 +1,33 @@
|
||||
-- task 1
|
||||
CREATE TABLE dist_table
|
||||
ENGINE = Distributed(
|
||||
'cluster_name', -- нет доступа к конфигу infra clickhouse
|
||||
'mdrozdov',
|
||||
'logs',
|
||||
rand()
|
||||
);
|
||||
--rand() это параметр по которому мы распределяем данные при insert на разные ноды, в данном
|
||||
--случае нам это нужно для равномерности распределения, потому что таблица не требует особых связей или тп
|
||||
|
||||
-- task 2
|
||||
--Создай VIEW top_active_users, который показывает топ-100 пользователей по числу событий
|
||||
CREATE VIEW top_active_users AS
|
||||
select user_id, count(*) as total_events
|
||||
from events
|
||||
group by user_id
|
||||
order by total_events desc
|
||||
limit 100
|
||||
-- не подходит для дашборда с миллионами строк, потому что вычисляется каждый раз при вызове
|
||||
-- для дашбордов лучше подойдет materialized view, тк хранит данные запроса и обновляется автоматически
|
||||
-- при вставке новых данных
|
||||
|
||||
--task 3
|
||||
CREATE MATERIALIZED VIEW
|
||||
ENGINE = SummingMergeTree
|
||||
order by date
|
||||
mv_clicks_per_day AS
|
||||
select
|
||||
toDate(event_time) as date,
|
||||
count(*) as total_clicks
|
||||
from raw_events
|
||||
group date
|
||||
Reference in New Issue
Block a user