LEFT JOIN ба RIGHT JOIN
INNER JOIN зөвхөн хоёр талд тохирох мөрүүдийг буцаадаг. LEFT JOIN ба RIGHT JOIN нь тохирохгүй мөрүүдийг ч хадгалдаг — энэ нь бодит системд маш их хэрэглэгддэг.
LEFT JOIN
Зүүн хүснэгтийн бүх мөрийг буцаана. Баруун хүснэгтэд тохирох мөр байхгүй бол NULL гарна.
SELECT багана
FROM зүүн_хүснэгт
LEFT JOIN баруун_хүснэгт ON нөхцөл;
Жишээ — захиалгагүй хэрэглэгчдийг олох:
SELECT
u.id,
u.name,
o.id AS захиалга_id
FROM users AS u
LEFT JOIN orders AS o ON u.id = o.user_id;
+----+------------------+-------------+
| id | name | захиалга_id |
+----+------------------+-------------+
| 1 | Болд Батбаяр | 1 |
| 1 | Болд Батбаяр | 2 |
| 2 | Дорж Гантулга | 3 |
| 3 | Мөнх Эрдэнэ | 4 |
| 4 | Энх Болд | NULL | ← захиалга байхгүй
+----+------------------+-------------+
INNER JOIN байсан бол Энх Болд харагдахгүй байсан. LEFT JOIN тул бүх хэрэглэгч харагдана.
NULL утга JOIN үр дүнд
LEFT JOIN-ийн баруун хүснэгтийн баганууд тохирол байхгүй үед NULL болно. Энийг ашиглан "тохирол байхгүй" мөрүүдийг шүүж болно:
-- Захиалга хийгээгүй хэрэглэгчид
SELECT u.id, u.name
FROM users AS u
LEFT JOIN orders AS o ON u.id = o.user_id
WHERE o.id IS NULL;
+----+----------+
| id | name |
+----+----------+
| 4 | Энх Болд |
+----+----------+
Энэ загвар — LEFT JOIN ... WHERE баруун_хүснэгт.id IS NULL — "A-д байгаа ч B-д байхгүй" мөрүүдийг олох стандарт арга юм.
LEFT JOIN-ий практик жишээнүүд
Хэрэглэгч бүрийн захиалгын тоо (захиалгагүй бол 0):
SELECT
u.name,
COUNT(o.id) AS захиалгын_тоо
FROM users AS u
LEFT JOIN orders AS o ON u.id = o.user_id
GROUP BY u.id, u.name
ORDER BY захиалгын_тоо DESC;
+------------------+---------------+
| name | захиалгын_тоо |
+------------------+---------------+
| Болд Батбаяр | 2 |
| Дорж Гантулга | 1 |
| Мөнх Эрдэнэ | 1 |
| Энх Болд | 0 | ← COUNT(NULL) = 0
+------------------+---------------+
COUNT(o.id) — NULL утгуудыг тоолохгүй, тиймээс захиалгагүй хэрэглэгчид 0 гарна. COUNT(*) бол NULL-ийг ч тоолох тул буруу үр дүн гарна.
Хичээл дуусгаагүй хэрэглэгчид:
SELECT u.name
FROM users AS u
LEFT JOIN lesson_progress AS lp
ON u.id = lp.user_id AND lp.course_slug = 'javascript'
WHERE lp.id IS NULL;
RIGHT JOIN
Баруун хүснэгтийн бүх мөрийг буцаана. Зүүн хүснэгтэд тохирох мөр байхгүй бол NULL гарна.
SELECT
u.name,
o.id AS захиалга_id
FROM orders AS o
RIGHT JOIN users AS u ON o.user_id = u.id;
Энэ нь дээрх LEFT JOIN жишээтэй яг адил үр дүн гарна — хүснэгтүүдийн дарааллыг сольсон.
+------------------+-------------+
| name | захиалга_id |
+------------------+-------------+
| Болд Батбаяр | 1 |
| Болд Батбаяр | 2 |
| Дорж Гантулга | 3 |
| Мөнх Эрдэнэ | 4 |
| Энх Болд | NULL |
+------------------+-------------+
Практикт: RIGHT JOIN маш ховор хэрэглэгддэг — LEFT JOIN-ийн хүснэгтийн дарааллыг сольсон хувилбар учир LEFT JOIN-ийг л ашиглаж, хүснэгтийн дарааллыг тохируулах нь уншихад хялбар.
INNER vs LEFT JOIN харьцуулалт
-- INNER JOIN: хоёуланд байгаа мөрүүд л
SELECT u.name, o.id
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- Захиалгагүй хэрэглэгч: харагдахгүй
-- LEFT JOIN: бүх хэрэглэгч
SELECT u.name, o.id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Захиалгагүй хэрэглэгч: NULL-тэй харагдана
Хэзээ аль нь:
| Нөхцөл | JOIN |
| ---------------------------------------------------- | ---------------------------------- |
| Хоёр хүснэгтэд хоёуланд нь байгаа мөрүүд | INNER JOIN |
| Зүүн хүснэгтийн бүгдийг, баруун хүснэгтийн тохирохыг | LEFT JOIN |
| "A-д байгаа ч B-д байхгүй" мөрүүд | LEFT JOIN ... WHERE b.id IS NULL |
FULL OUTER JOIN — MySQL-д UNION-оор
MySQL-д FULL OUTER JOIN шууд байхгүй. LEFT JOIN + RIGHT JOIN-ийг UNION-оор нэгтгэж хэрэгжүүлнэ:
-- Хоёр талын бүх мөр (тохирол байхгүй бол NULL)
SELECT u.name, o.id AS захиалга_id
FROM users AS u
LEFT JOIN orders AS o ON u.id = o.user_id
UNION
SELECT u.name, o.id AS захиалга_id
FROM users AS u
RIGHT JOIN orders AS o ON u.id = o.user_id;
UNION нь давтагдсан мөрүүдийг нэг болгоно. Давтагдсаныг хадгалах бол UNION ALL ашиглана.
Олон хүснэгттэй LEFT JOIN
SELECT
u.name AS хэрэглэгч,
COUNT(DISTINCT o.id) AS захиалга,
COALESCE(SUM(p.price * o.quantity), 0) AS нийт_зарцуулсан
FROM users AS u
LEFT JOIN orders AS o ON u.id = o.user_id
LEFT JOIN products AS p ON o.product_id = p.id
GROUP BY u.id, u.name
ORDER BY нийт_зарцуулсан DESC;
+------------------+----------+-----------------+
| хэрэглэгч | захиалга | нийт_зарцуулсан |
+------------------+----------+-----------------+
| Мөнх Эрдэнэ | 1 | 89900.00 |
| Болд Батбаяр | 2 | 33880.00 |
| Дорж Гантулга | 1 | 4990.00 |
| Энх Болд | 0 | 0.00 |
+------------------+----------+-----------------+
COALESCE(утга, анхдагч) — утга NULL бол анхдагч утгыг буцаана. Энд захиалгагүй хэрэглэгчийн нийт дүн NULL биш 0.00 болно.
Дараагийн хичээлд:
COUNT, SUM, AVG, MIN, MAX — нэгтгэх функцүүдийг GROUP BY-тай хамт ашиглах аргуудыг үзнэ.