← К оглавлению занятия

Занятие 23. Практикум 6

📁 Блок: SQL / MySQL / Связи и JOIN ⏱️ Время изучения: ~90 мин 🎯 Сложность: Практикум
#select #union #join #where #null #group #by #like

⚡ Кратко: типичные ошибки

  • UNION вместо UNION ALL — теряем источник строк.
  • INNER JOIN вместо LEFT JOIN — теряем заказы без связей.
  • Фильтр на RIGHT таблицу в WHERE при LEFT JOIN.

🐛 Типичные ошибки и исправления

Ошибка 1. UNION вместо UNION ALL

Неправильно:

SELECT company FROM employees
UNION
SELECT company FROM customers
UNION
SELECT company FROM suppliers;

Почему плохо: совпадающие названия компаний сольются, и невозможно понять, какая запись из какой таблицы.

Правильно: добавить столбец-источник и использовать UNION ALL.

SELECT company, 'employees' AS source FROM employees
UNION ALL
SELECT company, 'customers' AS source FROM customers
UNION ALL
SELECT company, 'suppliers' AS source FROM suppliers;

Ошибка 2. INNER JOIN для поиска записей без связи

Неправильно:

SELECT e.first_name, e.last_name
FROM employees AS e
INNER JOIN employee_privileges AS ep
  ON e.id = ep.employee_id
WHERE ep.employee_id IS NULL;  -- бессмысленно: INNER JOIN уже отбросил NULL

Почему плохо: INNER JOIN не допускает NULL в условии связи, поэтому результат будет пустым.

Правильно:

SELECT e.first_name, e.last_name
FROM employees AS e
LEFT JOIN employee_privileges AS ep
  ON e.id = ep.employee_id
WHERE ep.employee_id IS NULL;

Ошибка 3. INNER JOIN вместо LEFT JOIN для расшифровки заказов

Неправильно:

SELECT o.*, e.first_name
FROM orders AS o
INNER JOIN employees AS e
  ON o.employee_id = e.id
WHERE o.ship_city = 'Seattle';

Почему плохо: если у заказа не заполнен employee_id или сотрудник отсутствует, заказ пропадёт из результата.

Правильно: использовать LEFT JOIN, чтобы сохранить все заказы с Seattle.

Ошибка 4. Неправильный порядок фильтрации

Неправильно:

SELECT itt.type_name, COUNT(*) AS c
FROM inventory_transactions AS it
JOIN inventory_transaction_types AS itt
  ON it.transaction_type = itt.id
GROUP BY itt.type_name
WHERE itt.type_name NOT LIKE '%Sold%';

Почему плохо: WHERE нельзя ставить после GROUP BY. Для фильтрации групп используется HAVING; для фильтрации строк — WHERE до GROUP BY.

Правильно:

SELECT itt.type_name, COUNT(*) AS c
FROM inventory_transactions AS it
JOIN inventory_transaction_types AS itt
  ON it.transaction_type = itt.id
WHERE itt.type_name NOT LIKE '%Sold%'
GROUP BY itt.type_name;