Python
Junior
a
Ниже — КОНКРЕТНЫЕ ловушки + неправильный запрос → правильный → как это объяснять.
Именно так обычно «ловят» кандидатов.
Ответы
Отлично, это **самое ценное перед собеседованием** 🔥
Ниже — **КОНКРЕТНЫЕ ловушки + неправильный запрос → правильный → как это объяснять**.
Именно так обычно «ловят» кандидатов.
---
# 🧠 SQL / PostgreSQL — нюансы и ловушки с примерами
Используем таблицы:
```text
users(id, name, city)
orders(id, user_id, amount)
employees(id, department, salary)
```
---
## 🔥 ЛОВУШКА 1. `LEFT JOIN` + `WHERE` превращается в `INNER JOIN`
### 📌 Задача
**Показать всех пользователей и их заказы (если есть)**
❌ Неправильно:
```sql
SELECT u.name, o.id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.amount > 100;
```
👉 ❌ Пользователи без заказов **пропадут**
✅ Правильно:
```sql
SELECT u.name, o.id
FROM users u
LEFT JOIN orders o
ON u.id = o.user_id AND o.amount > 100;
```
🗣 Что сказать:
> «Фильтр, влияющий на JOIN, нужно писать в ON, иначе LEFT JOIN превратится в INNER JOIN»
---
## 🔥 ЛОВУШКА 2. `COUNT(*)` vs `COUNT(column)`
### 📌 Задача
**Посчитать количество заказов у пользователей**
```sql
SELECT user_id, COUNT(amount)
FROM orders
GROUP BY user_id;
```
👉 Если `amount` может быть `NULL` — результат будет **неполным**
✅ Чаще правильно:
```sql
SELECT user_id, COUNT(*)
FROM orders
GROUP BY user_id;
```
🗣 Фраза:
> «COUNT(column) не считает NULL, COUNT(*) считает строки»
---
## 🔥 ЛОВУШКА 3. `IN` и `NULL`
### 📌 Задача
**Найти пользователей, у которых есть заказы**
❌ Потенциально опасно:
```sql
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM orders);
```
👉 Если в `orders.user_id` есть `NULL`, результат может быть неожиданным.
✅ Надёжнее:
```sql
SELECT *
FROM users u
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
);
```
🗣 Фраза:
> «EXISTS безопаснее и лучше масштабируется»
---
## 🔥 ЛОВУШКА 4. `WHERE` с агрегатами
### 📌 Задача
**Найти города, где больше 5 пользователей**
❌ Неправильно:
```sql
SELECT city, COUNT(*)
FROM users
WHERE COUNT(*) > 5
GROUP BY city;
```
✅ Правильно:
```sql
SELECT city, COUNT(*)
FROM users
GROUP BY city
HAVING COUNT(*) > 5;
```
🗣 Фраза:
> «WHERE применяется до агрегации, HAVING — после»
---
## 🔥 ЛОВУШКА 5. `GROUP BY` и лишние поля
### 📌 Задача
**Посчитать пользователей по городам**
❌ Ошибка:
```sql
SELECT name, city, COUNT(*)
FROM users
GROUP BY city;
```
👉 `name` не в `GROUP BY` и не агрегирован
✅ Правильно:
```sql
SELECT city, COUNT(*)
FROM users
GROUP BY city;
```
🗣 Фраза:
> «Все неагрегированные поля должны быть в GROUP BY»
---
## 🔥 ЛОВУШКА 6. Оконные функции ≠ GROUP BY
### 📌 Задача
**Показать сотрудников и среднюю зарплату по отделу**
❌ Неправильно (теряются строки):
```sql
SELECT department, AVG(salary)
FROM employees
GROUP BY department;
```
✅ Правильно:
```sql
SELECT
department,
salary,
AVG(salary) OVER (PARTITION BY department)
FROM employees;
```
🗣 Фраза:
> «GROUP BY схлопывает строки, OVER — нет»
---
## 🔥 ЛОВУШКА 7. `RANK` vs `ROW_NUMBER`
### 📌 Задача
**Найти топ-1 сотрудника по зарплате**
❌ Ошибка логики:
```sql
SELECT *
FROM (
SELECT name, RANK() OVER (ORDER BY salary DESC) r
FROM employees
) t
WHERE r = 1;
```
👉 Вернёт **несколько строк**, если зарплаты одинаковые
✅ Если нужен ровно один:
```sql
SELECT *
FROM (
SELECT name, ROW_NUMBER() OVER (ORDER BY salary DESC) rn
FROM employees
) t
WHERE rn = 1;
```
🗣 Фраза:
> «ROW_NUMBER гарантирует одну строку»
---
## 🔥 ЛОВУШКА 8. `LIKE '%abc'` и индексы
### 📌 Задача
**Найти пользователей по части имени**
```sql
SELECT *
FROM users
WHERE name LIKE '%an%';
```
👉 ❌ B-tree индекс **не используется**
🗣 Фраза:
> «Поиск с ведущим `%` не использует обычный индекс»
(Если senior — можно упомянуть `GIN + pg_trgm`)
---
## 🔥 ЛОВУШКА 9. `CTE` — не всегда оптимизация
### 📌 Задача
**Использовать CTE для читаемости**
```sql
WITH big_orders AS (
SELECT * FROM orders WHERE amount > 1000
)
SELECT COUNT(*) FROM big_orders;
```
👉 В PostgreSQL CTE может быть **оптимизационным барьером**
🗣 Фраза:
> «CTE улучшает читаемость, но не всегда ускоряет запрос»
---
## 🔥 ЛОВУШКА 10. `UNION` по умолчанию удаляет дубликаты
### 📌 Задача
**Склеить списки**
```sql
SELECT name FROM users
UNION
SELECT name FROM employees;
```
👉 Сортировка + удаление дублей = медленно
✅ Если дубликаты не важны:
```sql
UNION ALL
```
🗣 Фраза:
> «UNION ALL быстрее, если дубликаты допустимы»
---
## 🔥 ЛОВУШКА 11. `DELETE` без WHERE
### 📌 Задача
**Удалить часть данных**
❌ Опасно:
```sql
DELETE FROM users;
```
🗣 Фраза:
> «На проде всегда сначала SELECT, потом DELETE»
---
## 🔥 ЛОВУШКА 12. `ORDER BY` в подзапросе
### 📌 Задача
**Найти максимальную зарплату**
❌ Бессмысленно:
```sql
SELECT *
FROM (
SELECT * FROM employees ORDER BY salary DESC
) t;
```
👉 `ORDER BY` **не гарантирован** без `LIMIT`
🗣 Фраза:
> «ORDER BY имеет смысл только в финальном запросе или с LIMIT»
---
# 🎯 Как это использовать на собеседовании
Если ты:
* замечаешь ловушку
* озвучиваешь её
* предлагаешь исправление
➡️ ты выглядишь **на уровень выше**, чем просто “пишущий SQL”.
---
Если хочешь:
* 🔥 **реальные задачи с собеседований (40+ ловушек)**
* 🔥 **симуляция live-coding**
* 🔥 **что отличает junior / middle / senior**
* 🔥 **как отвечать, если не знаешь ответ**
Скажи, **на какой уровень целишься** — сделаем финальную подготовку 💪