Files
homework/dmedvedev/10.5.Porydok.sql
T
Dmitry Medvedev 297df348c1 fixed mistakes
2026-08-05 23:51:40 +05:00

284 lines
14 KiB
SQL
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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** — Запрос с группировкой
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 мс соответственно)