MySQL / LEFT JOIN ба RIGHT JOIN

LEFT JOIN ба RIGHT JOIN

INNER JOIN зөвхөн хоёр талд тохирох мөрүүдийг буцаадаг. LEFT JOIN ба RIGHT JOIN нь тохирохгүй мөрүүдийг ч хадгалдаг — энэ нь бодит системд маш их хэрэглэгддэг.

LEFT JOIN

Зүүн хүснэгтийн бүх мөрийг буцаана. Баруун хүснэгтэд тохирох мөр байхгүй бол NULL гарна.

sql
SELECT багана
FROM зүүн_хүснэгт
LEFT JOIN баруун_хүснэгт ON нөхцөл;

Жишээ — захиалгагүй хэрэглэгчдийг олох:

sql
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 болно. Энийг ашиглан "тохирол байхгүй" мөрүүдийг шүүж болно:

sql
-- Захиалга хийгээгүй хэрэглэгчид
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):

sql
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-ийг ч тоолох тул буруу үр дүн гарна.

Хичээл дуусгаагүй хэрэглэгчид:

sql
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 гарна.

sql
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 харьцуулалт

sql
-- 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-оор нэгтгэж хэрэгжүүлнэ:

sql
-- Хоёр талын бүх мөр (тохирол байхгүй бол 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

sql
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-тай хамт ашиглах аргуудыг үзнэ.