Files

167 lines
6.4 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Задачи на отработку:
### **Задача 1.**
Таблица `products`
| product_id | name |
| --- | --- |
| 101 | iPhone 14 |
| 102 | Galaxy S22 |
| 103 | Pixel 7 |
Таблица `prices`
| product_id | price | region |
| --- | --- | --- |
| 101 | 999 | US |
| 101 | 1049 | EU |
| 102 | 850 | US |
| 102 | 899 | CA |
| 103 | 799 | JP |
1. Сделай `ANY LEFT JOIN`, чтобы получить цену **любой** из регионов.
SELECT
pr.product_id,
p.region,
pr.name,
p.price
FROM prices p
ANY LEFT JOIN products pr ON p.product_id = pr.product_id;
ЗДЕСЬ МЫ ПОЛУЧИМ НА ВЫХОДЕ 5 СТРОК.
А ЕСЛИ БЫ ДЖОЙНИЛИ ТАБЛИЦЫ НАОБОРОТ, ТО ПОЛУЧИЛИ БЫ 3 СТРОКИ.
2. Что будет, если в таблице `prices` несколько цен на один `product_id`?
ВСЕ БУДЕТ ЗАВИСЕТЬ ОТ СОЕДИНЕНИЯ ТАБЛИЦ. ЕСЛИ МЫ ДЖОЙНИМ К ТАБЛИЦЕ С product_id И НА КАЖДОЫЙ ЕСТЬ НЕСКОЛЬКО ЦЕН, ТО В ТАКОМ СЛУЧАЕ КЛИКХАУС ВОЗЬМЕТ ПЕРВОЕ ЗНАЧЕНИЕ С ДИСКА И ПРИСВОИТ ЕГО К product_id, А ОСТАЛЬНЫЕ ЗНАЧЕНИЯ ВЫБРОСИТ.
3. Как повлияет `ALL LEFT JOIN`? Почему в ClickHouse его избегают?
ИЗ-ЗА ПРИМЕНЕНИЯ ОЛЛ ЛЕФТ ДЖОЙН КЛИКХАУС НЕ СМОЖЕТ ВЫБРОСИТЬ НЕНУЖНЫЕ СТРОКИ И УЧТЕТ ВСЕ. В НАШЕМ ПРИМЕРЕ СТРОК СТАНЕТ 5.
ДАННЫЕ МОГУТ ПЕРЕГРУЖАТЬ ПАМЯТЬ И ТОРМОЗИТЬ СИСТЕМУ. МЕТРИКИ МОГУТ СЧИТАТЬСЯ ИСКАЖЕННЫМИ.
### **Задача 2.**
Таблица `ticks`
| time | symbol | price |
| --- | --- | --- |
| 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 |
Таблица `orders`
| time | symbol | size |
| --- | --- | --- |
| 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 |
1. Сделай `ASOF JOIN`, чтобы каждой сделке найти **предыдущую цену**.
SELECT
o.symbol,
o.size,
t.price,
o.time AS order_time,
t.time AS price_time
FROM orders o
ASOF LEFT JOIN ticks t ON o.symbol = t.symbol AND o.time >= t.time;
2. Почему нельзя использовать обычный `JOIN` по `time = time`?
КАК МИНИМУМ ПОТОМУ ЧТО ВРЕМЯ ПО СДЕЛКЕ И ВРЕМЯ ПО ТИКЕТУ НЕ СОВПАДАЕТ.
3. Сделай выборку только по `symbol = 'AAPL'`.
SELECT
o.symbol,
o.size,
t.price,
o.time AS order_time,
t.time AS price_time
FROM orders o
ASOF LEFT JOIN ticks t ON o.symbol = t.symbol AND o.time >= t.time
WHERE o.symbol = 'AAPL';
ИЛИ
SELECT
o.symbol,
o.size,
t.price,
o.time AS order_time,
t.time AS price_time
FROM
(
SELECT * FROM orders WHERE o.symbol = 'AAPL'
) AS o
ASOF LEFT JOIN
(
SELECT * FROM ticks WHERE o.symbol = 'AAPL'
) AS t
ON o.symbol = t.symbol AND o.time >= t.time;
### **Задача 3.**
Таблица `users`
| user_id | name |
| --- | --- |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
| 4 | Diana |
Таблица `payments`
| payment_id | user_id | amount |
| --- | --- | --- |
| 1001 | 1 | 500 |
| 1002 | 1 | 1500 |
| 1003 | 3 | 1200 |
| 1004 | 4 | 900 |
1. Верни всех пользователей, у которых **есть платежи** (через `WHERE user_id IN (...)`).
SELECT
u.user_id
FROM users u
WHERE user_id IN (SELECT user_id FROM payments);
2. Добавь условие: сумма платежа больше 1000.
SELECT
u.user_id
FROM users u
WHERE user_id IN (SELECT user_id FROM payments WHERE amount > 1000);
3. Почему это называют `SEMI JOIN`? Как это оптимизируется в ClickHouse?
Потому что это неполноценное соединение , а только проверяющее факт наличия того или иного условия.
Вообще по идее нужно было бы написать LEFT SEMI JOIN , в кликхаус видя конструкцию IN (SELECT...) уже сам понимает что это SEMI JOIN.
### **Задача 4.**
Таблица `big_logs` (упрощённый фрагмент)
| user_id | event_time | event_type |
| --- | --- | --- |
| 1 | 2025-07-17 08:00:00 | login |
| 2 | 2025-07-17 08:05:00 | view |
| 3 | 2025-07-17 08:10:00 | purchase |
| 1 | 2025-07-17 08:20:00 | logout |
| 2 | 2025-07-17 08:30:00 | click |
Таблица `users`
| user_id | name |
| --- | --- |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
1. Сделай `JOIN`, чтобы добавить `name` к каждому логу.
SELECT
bl.user_id,
bl.event_time,
bl.event_type,
u.name
FROM big_logs bl ANY LEFT JOIN users u ON bl.user_id = u.user_id;
2. Почему `users` нужно ставить **в правую часть JOIN**?
ПОТОМУ ЧТО ЭТА ТАБЛИЦА ЯВЛЯЕТСЯ МАЛЕНЬКОЙ И МОЖНО СКАЗАТЬ СПРАВОЧНОЙ, А ЛОГИ БУДУТ РАСТИ И РАСТИ. И ЕСЛИ ЕЕ ЗАГРУЗИТЬ В ОПЕРАТИВНУЮ ПАМЯТЬ, ТО МЫ МОЖЕМ РАНО ИЛИ ПОЗДНО ПОЛУЧИТЬ ОШИБКУ.
3. Как выбрать `ANY` или `ALL` — если `user_id` уникален?
ЕСЛИ МЫ УВЕРЕНЫ НА 100% ЧТО ОН УНИКАЛЕН ТО НУЖНО ВАЫБИРАТЬ ANY , В ТАКОМ СЛУЧАЕ СОХРАНЯЮТСЯ РЕСУРСЫ ПАМЯТИ. ALL ЖЕ ВЫБИРАЕТСЯ КОГДА НЕОБХОДИМО ДЕКАРТОВО ПРОИЗВЕДЕНИЕ.