Към съдържанието
wannacode

UNION, INTERSECT, EXCEPT и CROSS JOIN

Накратко: UNION събира резултатите на две заявки, INTERSECT оставя общите редове, EXCEPT маха от първия резултат редовете на втория, а CROSS JOIN дава всяка двойка редове.

Проблем

Един списък от две места

Магазинът праща есенен бюлетин на активните клиенти. Активен е всеки, който е поръчал от 1 септември 2026 г. или е писал отзив от 1 юни насам.

Поръчките и отзивите са в различни таблици. Ако ги свържеш с JOIN, ще останат само клиентите, които имат и двете. Трябват ни двата списъка, сложени един под друг.

Идеята

UNION

UNION слага резултата на втората заявка под този на първата и маха повторенията:

SQLбаза: магазин

11 клиенти. Всяка от двете заявки е цяла, със свой FROM, JOIN и WHERE. Имената на колоните идват от първата.

UNION ALL пази и повторенията:

SQLбаза: магазин

17 реда: петима клиенти се срещат повече от веднъж (с няколко поръчки или и с поръчка, и с отзив). За бюлетина е нужен UNION, иначе някой ще получи писмото три пъти. UNION ALL е за случаите, когато всеки ред е отделно събитие и трябва да се брои.

Пробвай

Дегустация на кафе

Магазинът кани на дегустация всички, които са купували кафе на зърна (продукт 17) или са писали отзив за него. Покажи имената им, всяко веднъж.

SQLбаза: магазин

Виж го

Колоните трябва да съвпадат

Двете заявки дават редове за една и съща таблица, затова броят на колоните им трябва да е еднакъв:

SQLбаза: магазин

Колоните се сдвояват по реда си, а не по имената. Ако първата заявка връща name, email, втората също трябва да връща две колони, и то в смислен ред: името под името.

За обща история на клиента сложи колона, която казва откъде е редът. Поръчките и отзивите на Мария, по дата:

SQLбаза: магазин

ORDER BY в края подрежда целия резултат, а не само втората заявка. Колоните се казват day и event, както в първата заявка.

Идеята

INTERSECT и EXCEPT

INTERSECT оставя редовете, които ги има и в двата резултата. Продуктите, които са и поръчвани, и с отзив:

SQLбаза: магазин

13 продукта. Това са точно продуктите с отзив, защото всеки продукт е поръчван (видя го в урока за LEFT JOIN).

EXCEPT оставя редовете от първия резултат, които ги няма във втория. Продуктите без отзив:

SQLбаза: магазин

12 продукта. Същото дава и LEFT JOIN reviews … WHERE r.id IS NULL. EXCEPT се чете като изречение: „всички продукти, без тези с отзив“. При EXCEPT редът на заявките е важен, а при UNION и INTERSECT не е.

Пробвай

Да поискаме отзив

Кои продукти са купувани от 1 септември 2026 г. насам, но нямат нито един отзив? На купувачите им ще се изпрати молба за отзив. Покажи имената на продуктите.

SQLбаза: магазин

Идеята

CROSS JOIN

Понякога ти трябва всяка двойка. Отчетът по градове и категории трябва да има ред за всеки град и всяка подкатегория, дори там, където продажби няма. Мрежата се прави с CROSS JOIN: всеки ред на едната таблица с всеки ред на другата, без ON.

SQLбаза: магазин

6 града по 6 подкатегории, 36 реда. DISTINCT е нужен, защото в customers градът се повтаря: без него редовете са 114, по един за всеки клиент с град и всяка подкатегория.

Да попълниш мрежата с продажбите (и с нулите) ще можеш в модула за подзаявките. Мрежата е първата половина.

Виж го

Внимание с броя на редовете

CROSS JOIN умножава. 60 поръчки и 152 реда на поръчки:

SQLбаза: магазин

9 120 двойки, почти всички безсмислени. Същото се случва, ако забравиш ON. В SQLite JOIN без ON е CROSS JOIN, без грешка:

SQLбаза: магазин

1 200 реда (60 × 20) вместо 60. PostgreSQL в този случай дава грешка. Ако отчетът изведнъж покаже много повече редове или пари от очакваното, първо провери условията в ON.

Упражнение

Мрежата на главните категории

Годишният отчет е по град и главна категория („Храни“, „Дом“). Направи мрежата: всеки град (без празния) с всяка главна категория, всяка двойка веднъж.

SQLбаза: магазин
По-точно, за любопитните

UNION в SQLite често връща редовете подредени, защото така маха повторенията. Това не е обещано. Щом редът е важен, пиши ORDER BY в края.

INTERSECT и EXCEPT ги има в SQLite, PostgreSQL и SQL Server. В Oracle EXCEPT се казва MINUS, а новите версии разбират и EXCEPT. MySQL ги има от версия 8.0.31.

Тест

Провери се

1. Каква е разликата между UNION и UNION ALL?
2. Кои продукти дава A EXCEPT B, ако A са поръчваните, а B тези с отзив?
3. Защо SELECT name, email … UNION SELECT name … дава грешка?
4. Таблица с 60 реда CROSS JOIN таблица със 152 реда. Колко реда излизат?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·