JOIN: две таблици в една заявка
Накратко: JOIN … ON слепва реда на едната таблица с реда на другата, към който сочи външният ключ, например поръчката с клиента ѝ, и оставя само редовете, които имат двойка.
Проблем
Поръчките с имената
Куриерската фирма иска списък: номер на поръчката, дата и името на клиента. Номерът и датата са в orders, името е в customers.
В миналия урок го правихме с две заявки и числото между тях го пренасяхме на ръка. За 60 поръчки това са 60 търсения. Трябва ни една заявка, която сама намира клиента на всяка поръчка.
Идеята
JOIN … ON
JOIN слага до всеки ред на едната таблица реда от другата, който му отговаря. ON казва кой ред на кой отговаря:
За всяка поръчка базата търси клиента, чието customers.id е равно на orders.customer_id, и ги слепва в един ред. Затова колоните се пишат с името на таблицата отпред: orders.id, customers.name.
Излизат 60 реда, колкото са поръчките: всяка поръчка има точно един клиент. Това се казва JOIN (или INNER JOIN): остават само двойките, които се намират. Теодора и Явор ги няма в списъка, защото нямат поръчки. Към тях ще се върнем в следващия урок.
На малки таблици се вижда как става: четири поръчки и трима клиенти, от които Теодора е без поръчки.
SELECT orders.id, orders.customer_id, customers.nameFROM ordersJOIN customers ON customers.id = orders.customer_id;Стъпка по стъпка, с думи
- 4 поръчки и 3 клиента. customer_id на поръчката е id на нейния клиент.
- Поръчка 1 има customer_id 2. Базата търси клиента с id 2: Георги Петров. Двойката става ред.
- Поръчка 2: customer_id 1, това е Мария Иванова.
- Поръчка 3 е пак на клиент 1: Мария Иванова е в резултата втори път.
- Поръчка 4 е пак на клиент 2: Георги Петров е в резултата втори път.
- Теодора Генова (id 3) не е customer_id на нито една поръчка. Няма двойка, затова я няма в резултата.
- 4 реда, колкото са поръчките. JOIN оставя само двойките, които се намират.
Същата заявка върху тези малки таблици. Пусни я и сравни с последната стъпка:
Идеята
Кратки имена
orders.ordered_at и customers.name стават дълги. На таблицата може да се даде кратко име за заявката: пишеш го след името ѝ във FROM и JOIN.
Същата заявка, същият резултат. o е orders, c е customers. Краткото име важи само в тази заявка. Може да пишеш и FROM orders AS o.
Пробвай
Новите поръчки
Покажи номера на новите поръчки (status е new) с името и имейла на клиента, за да им се изпрати потвърждение.
Решение
SELECT o.id, c.name, c.email
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'new';FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.status = 'new'. 11 поръчки. Имейлът е в customers, затова без JOIN няма как да го покажеш до поръчката.
Виж го
„ambiguous column name“
Ето заявка без имената на таблиците. Пусни я:
И orders, и customers имат колона id. След JOIN колоните на двете са заедно и базата не знае за коя id говориш. „Ambiguous“ значи „двусмислено“. Колоната name я има само в customers, затова за нея не се оплаква.
Решението е да кажеш от коя таблица е колоната:
Добрият навик е да пишеш краткото име пред всяка колона в заявка с JOIN, дори когато не е задължително. Който я чете, веднага вижда откъде е всяка колона.
Идеята
JOIN, WHERE и ORDER BY
След JOIN всичко познато работи както досега, а условията може да са върху колони и от двете таблици. Поръчките на клиентите от Варна, по дата:
Градът е в customers, датата е в orders. Редът на частите е: SELECT … FROM … JOIN … ON … WHERE … ORDER BY.
Пробвай
Какво има в поръчка 60
Покажи името на продукта, броя и цената за всеки ред на поръчка 60.
Решение
SELECT p.name, oi.quantity, oi.unit_price
FROM order_items oi
JOIN products p ON p.id = oi.product_id
WHERE oi.order_id = 60;FROM order_items oi JOIN products p ON p.id = oi.product_id WHERE oi.order_id = 60. Бял хляб, 2 броя по 1,20 €, и препарат за съдове, 4 броя по 2,90 €. Същото, което в урока „Магазинът“ събирахме с очи.
Упражнение
Две задачи
1. Магазинът проверява защо се отказват поръчки. Покажи номера на отказаните поръчки (cancelled) с името и града на клиента.
Отказаните поръчки с клиента и града му:
Решение
SELECT o.id, c.name, c.city
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'cancelled';JOIN customers c ON c.id = o.customer_id WHERE o.status = 'cancelled'. 7 поръчки. Поръчка 19 е на Борис, който е без град: JOIN е по id, затова празният град не пречи и той излиза с NULL.
2. Отделът за качество иска отзивите с оценка 3 или по-ниска заедно с името на продукта, за да знае какво да провери.
Ниските оценки: продуктът, оценката и текстът на отзива:
Решение
SELECT p.name, r.rating, r.body
FROM reviews r
JOIN products p ON p.id = r.product_id
WHERE r.rating <= 3;FROM reviews r JOIN products p ON p.id = r.product_id WHERE r.rating <= 3. Четири отзива: за кафето (1), праха за пране (2), тигана (3) и минералната вода (3).
По-точно, за любопитните
Ще срещнеш и по-стария запис: таблиците във FROM със запетая, а условието за двойките в WHERE.
Резултатът е същият. Записът с JOIN … ON държи условието за свързване отделно от условията за филтриране. Затова в курса пишем JOIN.
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: WHERE: филтриране на редове · NULL: няма стойност · ORDER BY, LIMIT и DISTINCT · Първичен и външен ключ
- Продължава в: LEFT JOIN: и редовете без двойка · Много таблици и таблица със себе си · UNION, INTERSECT, EXCEPT и CROSS JOIN · Подзаявки
- Задачи по темата: Свързване на таблици