LEFT JOIN: и редовете без двойка
Накратко: LEFT JOIN пази всички редове на лявата таблица, дори тези без двойка в дясната, и попълва липсващите колони с NULL.
Проблем
Кой не е поръчал?
Маркетингът иска да пише на клиентите, които са се регистрирали, но още нищо не са поръчали. В миналия урок JOIN върна 60 реда и в тях Теодора и Явор ги нямаше.
JOIN пази само двойките. Ред без двойка изчезва без предупреждение. Тук точно тези редове ни трябват.
Идеята
LEFT JOIN
Сравни двете заявки. Първата е с JOIN:
Втората е с LEFT JOIN:
62 реда вместо 60. LEFT JOIN пази всеки ред на лявата таблица (тази във FROM), дори да няма двойка в дясната. Където двойка няма, колоните на дясната таблица са NULL. Слез до края: Теодора и Явор са там, с NULL за номера и датата.
Оттук клиентите без поръчки са на една крачка:
WHERE o.id IS NULL оставя само редовете, при които поръчка не е намерена. Проверяваме o.id, защото първичният ключ на намерена поръчка никога не е празен.
Виж го
Празният отговор също е отговор
Има ли продукти, които никой не е поръчвал? Същият подход, с order_items:
Нито един ред. Всеки от 25-те продукта е поръчан поне веднъж. Таблица без редове не е грешка: заявката е отговорила „няма такива“.
Пробвай
Празните категории
Кои категории нямат нито един продукт пряко в тях? Покажи името на категорията.
Решение
SELECT cat.name
FROM categories cat
LEFT JOIN products p ON p.category_id = cat.id
WHERE p.id IS NULL;FROM categories cat LEFT JOIN products p ON p.category_id = cat.id WHERE p.id IS NULL. „Храни“ и „Дом“. Това са главните категории: продуктите са в подкатегориите им. С обикновен JOIN те изобщо не излизат.
Виж го
Броят с нулите
Колко поръчки има всеки клиент, заедно с тези без поръчки? Първи опит с COUNT(*):
Теодора и Явор имат по 1 поръчка? Не. COUNT(*) брои редове, а LEFT JOIN им даде по един ред, пълен с NULL. Брой това, което има стойност, COUNT(o.id):
COUNT(колона) пропуска NULL-ите, затова за тях излиза 0. При LEFT JOIN брой колона от дясната таблица, най-добре първичния ѝ ключ.
Пробвай
Отзивите на продуктите
Покажи всеки продукт и колко отзива има, включително продуктите без отзив (с 0).
Решение
SELECT p.name, COUNT(r.id) AS reviews
FROM products p
LEFT JOIN reviews r ON r.product_id = p.id
GROUP BY p.id, p.name;FROM products p LEFT JOIN reviews r ON r.product_id = p.id GROUP BY p.id, p.name и COUNT(r.id). 25 реда. С COUNT(*) продуктите без отзив щяха да са с 1, а с JOIN щяха да липсват.
Виж го
Капанът с WHERE
Отчет за октомври: всички клиенти и колко поръчки са направили от 1 октомври 2026 г. Условието за датата отива в WHERE:
Пет реда, а клиентите са 20. Условие за дясната таблица в WHERE превръща LEFT JOIN в обикновен JOIN. Мястото му е в ON: така то казва кои поръчки да се свържат, а клиентите остават всичките.
20 клиенти, повечето с 0. Правилото: условие за дясната таблица при LEFT JOIN пишеш в ON. Изключение е IS NULL, когато търсиш липсващите.
Упражнение
Две задачи
1. Магазинът ще кани за отзив клиентите, които още не са писали. Кои са те? Покажи името.
Клиентите без нито един отзив:
Решение
SELECT c.name
FROM customers c
LEFT JOIN reviews r ON r.customer_id = c.id
WHERE r.id IS NULL;FROM customers c LEFT JOIN reviews r ON r.customer_id = c.id WHERE r.id IS NULL. Шестима: Петя, Мартин, Симона, Христо, Теодора и Явор.
2. Кампанията „Липсваш ни“ е за клиентите, които нямат поръчка от 1 юли 2026 г. насам (включително тези, които никога не са поръчвали). Покажи името и имейла.
Клиентите без поръчка от 2026-07-01 насам:
Решение
SELECT c.name, c.email
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id AND o.ordered_at >= '2026-07-01'
WHERE o.id IS NULL;Датата отива в ON, а IS NULL в WHERE: LEFT JOIN orders o ON o.customer_id = c.id AND o.ordered_at >= '2026-07-01' WHERE o.id IS NULL. 10 клиенти. Ако датата е в WHERE, не излиза никой: редовете с NULL отпадат заради датата, а редовете с дата отпадат заради IS NULL.
По-точно, за любопитните
Има и RIGHT JOIN (пази редовете на дясната таблица) и FULL JOIN (пази и двете страни). SQLite ги разбира от версия 3.39. RIGHT JOIN се пише рядко: същото е LEFT JOIN с разменени таблици. MySQL няма FULL JOIN.
Тук излизат само клиентите без поръчки, защото всяка поръчка има клиент.
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: Агрегатни функции: COUNT, SUM, AVG · GROUP BY: отчет по групи · Първичен и външен ключ · JOIN: две таблици в една заявка
- Продължава в: Много таблици и таблица със себе си · UNION, INTERSECT, EXCEPT и CROSS JOIN · Отчет на стъпки: WITH · Дървета и редици: WITH RECURSIVE
- Задачи по темата: Свързване на таблици