284 lines
14 KiB
SQL
284 lines
14 KiB
SQL
- **Задача 1** — Запрос с группировкой
|
||
|
||
SELECT country, COUNT(*) AS users_count
|
||
FROM users
|
||
WHERE is_active = true
|
||
GROUP BY country
|
||
HAVING COUNT(*) > 1
|
||
ORDER BY users_count DESC;
|
||
|
||
**❓ Вопросы:**
|
||
|
||
1. Когда применится `WHERE` — до или после `GROUP BY`?
|
||
До группировки, потому что это фильтрация строк
|
||
2. Когда применится `HAVING` — до или после `GROUP BY`?
|
||
После группировки, потому что это фильтрация групп
|
||
3. Можно ли использовать алиас `users_count` в `HAVING`?
|
||
Нельзя, тк HAVING применяется до SELECT
|
||
4. Можно ли использовать алиас `users_count` в `ORDER BY`?
|
||
Можно, тк ORDER BY применяется после SELECT
|
||
|
||
|
||
- **Задача 2** — JOIN с фильтрацией
|
||
|
||
SELECT u.name, o.order_date, o.status
|
||
FROM users u
|
||
JOIN orders o ON u.id = o.user_id
|
||
WHERE u.country = 'Россия' AND o.status = 'completed'
|
||
ORDER BY o.order_date DESC;
|
||
|
||
**✅ Задание:**
|
||
|
||
- Опиши порядок выполнения своими словами (как будто объясняешь другу-новичку).
|
||
На самом первом этапе идет формирование таблицы данных из фром и джойна, далее данные отфильтровываются в WHERE и выполняется вычисление выражение черезе SELECT, в конечном счете строки фильруются по order_date через ORDER BY
|
||
|
||
- **Задача 3** — Найди ошибку
|
||
|
||
Дан запрос:
|
||
|
||
SELECT country, AVG(age) AS avg_age
|
||
FROM users
|
||
GROUP BY country
|
||
HAVING country = 'Россия';
|
||
|
||
**❓ Вопросы:**
|
||
|
||
1. Запрос работает, но написан **неэффективно**. Почему?
|
||
Потому что фильтрация по "Россия" идет в самом конце запроса, когда можно было на первоначальном этапе сделать через WHERE, чтобы не читать всю таблицу. Плюс можно добавить индекс по столюцу country
|
||
2. Перепиши его правильно, используя WHERE.
|
||
SELECT
|
||
country,
|
||
AVG(age) AS avg_age
|
||
FROM users
|
||
WHERE country = 'RU'
|
||
GROUP BY country;
|
||
3. Объясни, почему твой вариант быстрее.
|
||
Объяснил в 1ом вопросе.
|
||
|
||
- **Задача 4** — Исправь запрос
|
||
|
||
SELECT category, AVG(price) AS avg_price
|
||
FROM products
|
||
GROUP BY category
|
||
HAVING category = 'Электроника' AND AVG(price) > 20000;
|
||
|
||
**✅ Задание:**
|
||
|
||
1. Перепиши запрос так, чтобы часть условий была в `WHERE`.
|
||
SELECT category, AVG(price) AS avg_price
|
||
FROM products
|
||
WHERE category = 'Электроника'
|
||
GROUP BY category
|
||
HAVING AVG(price) > 20000;
|
||
2. Объясни, почему это быстрее.
|
||
Потому что сразу происходит фильтрация строк и дальнейшая группировка и фильтрация уже не затрагивает ненужные строки (чем раньше фильтрация, тем лучше)
|
||
3. Нарисуй схему: сколько строк будет обработано в каждом случае.
|
||
Если не исполбзовать WHERE , то ан этапе группировке на входе будет 7 строк , которые далее отфильтуются.
|
||
А если сразу использовать WHERE, то на входе в группировку будет всего три строки
|
||
|
||
- **Задача 5** — Исправь все ошибки
|
||
|
||
SELECT
|
||
country,
|
||
COUNT(*) AS users_count
|
||
FROM users
|
||
WHERE users_count > 1
|
||
GROUP BY country
|
||
ORDER BY country;
|
||
|
||
**✅ Задание:**
|
||
|
||
- Найди ошибку и исправь запрос.
|
||
|
||
SELECT
|
||
country,
|
||
COUNT(*) AS users_count
|
||
FROM users
|
||
--WHERE users_count > 1
|
||
GROUP BY country
|
||
HAVING COUNT(*) > 1 --добавлена фильтрация по группам
|
||
ORDER BY country;
|
||
- **Задача 6** — Полный цикл выполнения
|
||
|
||
SELECT
|
||
u.country,
|
||
COUNT(o.id) AS orders_count,
|
||
AVG(o.id) AS avg_order_id
|
||
FROM users u
|
||
LEFT JOIN orders o ON u.id = o.user_id
|
||
WHERE u.is_active = true
|
||
GROUP BY u.country
|
||
HAVING COUNT(o.id) > 1
|
||
ORDER BY orders_count DESC
|
||
LIMIT 3;
|
||
|
||
**✅ Задание:**
|
||
|
||
- Опиши ПОЛНЫЙ порядок выполнения (все 7 шагов) и объясни, что происходит на каждом.
|
||
1. Формирование таблицы данных из FROM и JOIN
|
||
2. Фильтрация строк WHERE
|
||
3. Группировка строк GROUP BY
|
||
4. Фильтрация групп HAVING
|
||
5. Вывод столбцов SELECT
|
||
6. Сортировка ORDER BY
|
||
7. Лимитирование выхода строк LIMIT
|
||
|
||
- **Задача 7** — Оптимизация
|
||
|
||
Сравни два запроса:
|
||
|
||
-- Запрос А
|
||
SELECT category, COUNT(*)
|
||
FROM products
|
||
GROUP BY category
|
||
HAVING category = 'Электроника';
|
||
|
||
-- Запрос Б
|
||
SELECT category, COUNT(*)
|
||
FROM products
|
||
WHERE category = 'Электроника'
|
||
GROUP BY category;
|
||
|
||
**❓ Вопросы:**
|
||
|
||
1. Какой запрос быстрее? Почему?
|
||
Запрос 2 быстрее потому что на этапе WHERE сразу отфильтровываются ненужные строки.
|
||
|
||
2. Нарисуй таблицу: на каком шаге сколько строк обрабатывается в каждом запросе.
|
||
На этапе FROM всего 7 строк. Далее если смотреть по запросу А они превращаются в 4 строки и на HAVING в 1.
|
||
Если смотреть на запрос Б, то после FROM остается 3 строки, содержащие данные только о категории 'Электроника', далее они просто группируются в одну.
|
||
|
||
3. Выполни оба с `EXPLAIN ANALYZE` и сравни `Execution Time.`
|
||
Запрос А - 0.04 мс
|
||
Запрос Б - 0.03 мс
|
||
|
||
|
||
|
||
- **Задача 8** — Многоэтапная фильтрация
|
||
|
||
SELECT
|
||
u.name,
|
||
COUNT(o.id) AS orders_count
|
||
FROM users u
|
||
LEFT JOIN orders o ON u.id = o.user_id
|
||
WHERE u.country = 'Россия'
|
||
AND u.age > 25
|
||
AND o.status = 'completed'
|
||
GROUP BY u.name
|
||
HAVING COUNT(o.id) >= 2
|
||
ORDER BY orders_count DESC;
|
||
|
||
**❓ Вопросы:**
|
||
|
||
1. Когда применяются условия `WHERE`?
|
||
Для фильтрации строк
|
||
2. Когда применяется условие `HAVING`?
|
||
Для фильтрации групп
|
||
3. В чём разница между фильтрацией по `o.status` в `WHERE` и по `COUNT(o.id)` в `HAVING`?
|
||
В WHERE фильтрация подразумевает выполненные заказы, а в HAVING подразумевает более 2х штук. Соответственно получается, что сначала мы фильтруем выполненные заказы, а потом людей у которых заказов более 2х штук.
|
||
|
||
|
||
- **Задача 9** — JOIN и ORDER BY
|
||
|
||
SELECT
|
||
u.name,
|
||
p.name AS product_name,
|
||
p.price
|
||
FROM users u
|
||
JOIN orders o ON u.id = o.user_id
|
||
JOIN order_items oi ON o.id = oi.order_id
|
||
JOIN products p ON oi.product_id = p.id
|
||
WHERE u.country = 'Россия'
|
||
ORDER BY p.price DESC
|
||
LIMIT 5;
|
||
|
||
**❓ Вопросы:**
|
||
|
||
1. На каком этапе применяется `ORDER BY`?
|
||
После FROM, JOIN, WHERE, SELECT и до LIMIT.
|
||
|
||
2. Почему `LIMIT` идёт после `ORDER BY`, а не до?
|
||
В таком случае нарушалась бы логика использования этих двух функций. Например, нужно вывести топ-3 (или топ-3 наименьшие) позиции из списка. И если лимит стоял бы до сортировки, то мы могли бы вывести совсем не топ значения. Данная последовательность помогает сначала сделать сортировка вверх или вниз и потом вывести нужные строки.
|
||
|
||
3. Что будет, если поменять их местами (технически невозможно, но подумай концептуально)?
|
||
В таком случае нарушалась бы логика использования этих двух функций. Например, нужно вывести топ-3 (или топ-3 наименьшие) позиции из списка. И если лимит стоял бы до сортировки, то мы могли бы вывести совсем не топ значения. Данная последовательность помогает сначала сделать сортировка вверх или вниз и потом вывести нужные строки.
|
||
|
||
- **Задача 10** — Напиши запрос с нуля
|
||
|
||
✅ Тебе нужно получить:
|
||
|
||
- Список категорий товаров
|
||
- Количество товаров в каждой категории
|
||
- Среднюю цену товаров в категории
|
||
- Только те категории, где средняя цена > 15000
|
||
- Только те категории, где товаров >= 2
|
||
- Отсортировать по средней цене (от большей к меньшей)
|
||
- Взять только топ-3
|
||
|
||
**✅ Задание:**
|
||
|
||
1. Напиши запрос
|
||
|
||
SELECT
|
||
p.category AS category,
|
||
COUNT(*) AS count_product_in_category,
|
||
AVG(price) AS avg_price_product_in_category
|
||
FROM products p
|
||
GROUP BY p.category
|
||
HAVING AVG(price) > 15000 AND COUNT(*) >= 2
|
||
ORDER BY avg_price_product_in_category DESC
|
||
LIMIT 3;
|
||
|
||
2. Опиши порядок выполнения
|
||
1. Формируется таблица из FROM
|
||
2. Группировка GROUP BY (Так как строки фильтровать не нужно)
|
||
3. Фильтрация групп HAVING
|
||
4. Вывод значений SELECT
|
||
5. Сортировка ORDER BY
|
||
6. Лимитирование LIMIT
|
||
|
||
3. Объясни, почему использовал `WHERE` или `HAVING` для каждого условия
|
||
Использовал только HAVING потому что по условию нужно фильтровать именно группы, а не строки.
|
||
|
||
4. Выполни с `EXPLAIN ANALYZE` и посмотри план
|
||
1. чтение таблицы products
|
||
2. Группировка с фильтрацией групп (hash aggregate)
|
||
3. Сортировка Sort key
|
||
4. LIMIT
|
||
|
||
|
||
- **Задача 11** — Подзапросы и порядок
|
||
|
||
SELECT
|
||
u.name,
|
||
u.age,
|
||
(SELECT COUNT(*)
|
||
FROM orders o
|
||
WHERE o.user_id = u.id) AS orders_count
|
||
FROM users u
|
||
WHERE u.country = 'Россия'
|
||
ORDER BY orders_count DESC;
|
||
|
||
**❓ Вопросы:**
|
||
|
||
1. Когда выполняется подзапрос в `SELECT`?
|
||
Подзапрос в SELECT вычисляется после того, как отработали секции FROM и WHERE
|
||
|
||
2. Можно ли использовать алиас `orders_count` в `WHERE`?
|
||
Нет, потому что WHERE не видит алиасы
|
||
|
||
3. Можно ли использовать его в `ORDER BY`?
|
||
Да, потому что order by выполняется после SELECT
|
||
|
||
4. Перепиши этот запрос через `JOIN`. Какой вариант быстрее? Проверь с `EXPLAIN ANALYZE`!
|
||
SELECT
|
||
u.name,
|
||
u.age,
|
||
COUNT(o.id) AS orders_count
|
||
FROM users u
|
||
LEFT JOIN orders o ON o.user_id = u.id
|
||
WHERE u.country = 'Россия'
|
||
GROUP BY u.id, u.name, u.age
|
||
ORDER BY orders_count DESC;
|
||
|
||
Второй запрос через JOIN выполняется быстрее (0.13 и 0.1 мс соответственно) |