JOIN

មាតិកា

  1. ហេតុអ្វីបានជាមាន Join
  2. INNER JOIN៖ យកតែគូដែលត្រូវគ្នា
  3. Table Alias និងការអាន Join
  4. LEFT JOIN៖ រក្សាទាំងអស់ពីខាងឆ្វេង
  5. ការរកជួរដែលគ្មានគូ (Anti-Join)
  6. RIGHT JOIN និង FULL JOIN
  7. CROSS JOIN
  8. Self Join
  9. ការ Join Table បីឬបួន
  10. ON ទល់នឹង USING
  11. កំហុសទី 1៖ ការគុណជួរ
  12. កំហុសទី 2៖ ការ Filter LEFT JOIN ក្នុង WHERE
  13. សាកល្បងដោយខ្លួនឯង

1. ហេតុអ្វីបានជាមាន Join

នៅជំពូកមុន អ្នកបានបំបែកទិន្នន័យរបស់ហាងទៅជា table ប្រាំ។ order មិនរក្សាទុកឈ្មោះអតិថិជនទេ។ វារក្សាទុក customer_id ដែលជាលេខចង្អុលទៅជួរមួយក្នុង customers។ ជួរនៃ order line ក៏មិនរក្សាទុកឈ្មោះផលិតផលដែរ។ វារក្សាទុក product_id។

ការបំបែកនេះធ្វើដោយចេតនា។ ឈ្មោះ "Sokha Chan" មាននៅត្រឹមតែកន្លែងតែមួយ ដូច្នេះការផ្លាស់ប្តូរវាគឺគ្រាន់តែ update មួយជួរ។ ប៉ុន្តែវាបង្កើតតម្រូវការថ្មី៖ ដើម្បីបោះពុម្ព "Sokha Chan ordered a Wireless Mouse" អ្នកត្រូវនាំជួរពី table ជាច្រើនមកផ្សំគ្នាវិញ។

នោះហើយជាអ្វីដែល join ធ្វើ។ join យក table ពីរមកបង្កើតជាលទ្ធផលរួមតែមួយ ដោយផ្គូផ្គងជួរតាមច្បាប់ដែលអ្នកសរសេរ។ ច្បាប់នោះស្ទើរតែជានិច្ចគឺ "foreign key ស្មើនឹង primary key"។

អ្វីៗទាំងអស់ក្នុងជំពូកនេះប្រើទិន្នន័យ shopdb ពីជំពូកមុនៗ។ ដាក់ query ទៅក្នុងឯកសារថ្មី shopdb/queries/07_joins.sql ហើយដំណើរការវាដោយ៖

docker exec -i shopdb-pg psql -U postgres -d shopdb < queries/07_joins.sql

ឬ paste វាចូលទៅក្នុង session psql អន្តរកម្ម។ សូមរំលឹក នេះគឺជា table តូចពីរដែលយើងចាប់ផ្តើម៖

customers                         orders
 id | name        | city           id | customer_id | status
----+-------------+------------   ----+-------------+----------
  1 | Sokha Chan  | Phnom Penh      1 |           1 | paid
  2 | Dara Kim    | Siem Reap       2 |           1 | shipped
  3 | Linda Vong  | Phnom Penh      3 |           2 | pending
  4 | Vuthy Sok   | Battambang      4 |           3 | paid
  5 | Maly Ros    | (null)          5 |           2 | cancelled

សូមកត់សម្គាល់ថា អតិថិជនទី 4 និងទី 5 (Vuthy និង Maly) គ្មាន order ទេ។ ពួកគេនឹងមានសារៈសំខាន់ខ្លាំងក្នុងជំពូកនេះ។

2. INNER JOIN៖ យកតែគូដែលត្រូវគ្នា

INNER JOIN រក្សាតែគូនៃជួរដែលលក្ខខណ្ឌ ON ពិត។ ជួរដែលគ្មានគូនៅម្ខាងទៀតនឹងបាត់ទៅ។

SELECT c.name, o.id AS order_id, o.status
FROM customers c
INNER JOIN orders o ON o.customer_id = c.id
ORDER BY o.id;
    name    | order_id |  status
------------+----------+-----------
 Sokha Chan |        1 | paid
 Sokha Chan |        2 | shipped
 Dara Kim   |        3 | pending
 Linda Vong |        4 | paid
 Dara Kim   |        5 | cancelled
(5 rows)

អាន query ឮៗ៖ "យកអតិថិជនគ្រប់គ្នា ហើយសម្រាប់ម្នាក់ៗ រក order ដែល customer_id ស្មើនឹង id របស់អតិថិជន។" Sokha មាន order ពីរ ដូច្នេះ Sokha លេចឡើងពីរដង។ Vuthy និង Maly គ្មាន ដូច្នេះពួកគេបាត់ពីលទ្ធផល។

ពាក្យ INNER ជាជម្រើស។ JOIN តែឯកឯងមានន័យថា INNER JOIN ហើយមនុស្សភាគច្រើនសរសេរបែបនេះ។

នេះគឺជារូបភាពដែលត្រូវចងចាំ។ គិតថា table នីមួយៗជាសំណុំនៃជួរ ហើយ join ជាផ្នែកត្រួតគ្នា៖

customers          orders
 (1)  --------------- (order 1, 2)
 (2)  --------------- (order 3, 5)
 (3)  --------------- (order 4)
 (4)   (no match)
 (5)   (no match)

inner join រក្សាតែបន្ទាត់នៅកណ្តាល។

3. Table Alias និងការអាន Join

សូមមើលអ្វីដែលយើងបានវាយ៖ FROM customers c។ c គឺជា alias ដែលជាឈ្មោះខ្លីសម្រាប់ table មានសុពលភាពតែក្នុង query នេះប៉ុណ្ណោះ។ alias ជួយសន្សំការវាយ ហើយសំខាន់ជាងនេះ គឺលុបភាពមិនច្បាស់លាស់។ ទាំង customers និង orders មាន column ឈ្មោះ id។ ប្រសិនបើអ្នកសរសេរតែ id PostgreSQL នឹងឈប់ជាមួយ៖

ERROR:  column reference "id" is ambiguous
LINE 1: SELECT id FROM customers c JOIN orders o ON o.customer_id = ...

ការសរសេរ c.id ឬ o.id ប្រាប់ច្បាស់ថាអ្នកមានន័យមួយណា។ ទម្លាប់ដែលត្រូវបណ្តុះ៖ ដាក់ alias នៅមុខ column ជានិច្ចក្នុង query ណាដែលមាន join ទោះបីវាមិនចាំបាច់ក៏ដោយ។ ប្រាំមួយខែក្រោយ អ្នកនឹងអរគុណខ្លួនឯង។

វិធីអាន join ដែលអាចទុកចិត្តបានគឺអានពីឆ្វេងទៅស្តាំ តាមលំដាប់ម្តងមួយ table៖

  1. ចាប់ផ្តើមពី customers (ហៅវាថា c)។
  2. សម្រាប់ជួរនីមួយៗរបស់វា រកក្នុង orders (ហៅវាថា o) នូវជួរដែល o.customer_id = c.id។
  3. បញ្ចេញជួរលទ្ធផលមួយសម្រាប់គូដែលត្រូវគ្នានីមួយៗ។

alias ក៏អនុញ្ញាតឲ្យអ្នកប្តូរឈ្មោះ column លទ្ធផលដោយ AS ដូចដែលយើងបានធ្វើជាមួយ o.id AS order_id ដើម្បីកុំឲ្យលទ្ធផលបង្ហាញ column ពីរដែលមានឈ្មោះ id ដូចគ្នា។

4. LEFT JOIN៖ រក្សាទាំងអស់ពីខាងឆ្វេង

ចុះបើអ្នកចង់បានបញ្ជីអតិថិជន ទាំងអស់ ជាមួយ order របស់ពួកគេពេលពួកគេមាន? inner join ទម្លាក់ Vuthy និង Maly។ LEFT JOIN រក្សារាល់ជួរពី table ខាងឆ្វេង ហើយបំពេញ column របស់ខាងស្តាំដោយ NULL ពេលគ្មានគូត្រូវគ្នា។

SELECT c.name, o.id AS order_id, o.status
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
ORDER BY c.id, o.id;
    name    | order_id |  status
------------+----------+-----------
 Sokha Chan |        1 | paid
 Sokha Chan |        2 | shipped
 Dara Kim   |        3 | pending
 Dara Kim   |        5 | cancelled
 Linda Vong |        4 | paid
 Vuthy Sok  |          |
 Maly Ros   |          |
(7 rows)

កោសិកាទទេគឺ NULL។ (តាមលំនាំដើម psql បោះពុម្ព NULL ជាខ្សែអក្សរទទេ។ អ្នកអាចប្តូរវាដោយ \pset null '(null)' ដែលមានប្រយោជន៍ពេលកំពុងរៀន។) ប្រាំពីរជួរ៖ គូដែលត្រូវគ្នាប្រាំ បូកជួរមួយសម្រាប់អតិថិជនពីរនាក់ដែលគ្មាន order។

"Left" ត្រឹមតែមានន័យថា table ដែលសរសេរ មុន ពាក្យ JOIN។ ក្នុងករណីនេះគឺ customers។ ប្តូរលំដាប់ table នោះអ្នកនឹងបាន query ផ្សេង។

LEFT JOIN ក៏សរសេរជា LEFT OUTER JOIN ដែរ។ វាជារបស់តែមួយ។

ច្បាប់ជ្រើសរើសសាមញ្ញ៖ ប្រសិនបើសំណួរគឺ "សម្រាប់ X នីមួយៗ បង្ហាញ Y របស់វា ហើយខ្ញុំនៅតែចង់បាន X ទោះគ្មាន Y" សូមប្រើ LEFT JOIN ដោយដាក់ X នៅខាងឆ្វេង។ ប្រសិនបើអ្នកចាប់អារម្មណ៍តែជួរ X ដែលមាន Y សូមប្រើ JOIN។

5. ការរកជួរដែលគ្មានគូ (Anti-Join)

សំណួរទូទៅខ្លាំងមួយគឺបញ្ច្រាស់វិញ៖ "តើអតិថិជនណាខ្លះដែល មិនធ្លាប់ ទិញ?" នេះហៅថា anti-join គឺជួរពី table មួយដែលគ្មានគូនៅក្នុង table មួយទៀត។

LEFT JOIN ផ្តល់វិធីល្អមួយ។ បន្ទាប់ពី left join អតិថិជនដែលគ្មាន order មាន NULL ក្នុងគ្រប់ column របស់ o។ ដូច្នេះរក្សាតែជួរទាំងនោះ៖

SELECT c.name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL
ORDER BY c.id;
   name
-----------
 Vuthy Sok
 Maly Ros
(2 rows)

យើងសាកល្បង o.id IS NULL ព្រោះ id ជា primary key ហើយមិនអាចជា NULL ក្នុងជួរពិតបានទេ ដូច្នេះ NULL នៅទីនោះអាចមានន័យតែ "គ្មានគូ" ប៉ុណ្ណោះ។ ត្រូវសាកល្បង column ដែលធានាថាមិនមែន null ជានិច្ច កុំប្រើ column ដូចជា o.status ដែលអាចជា NULL សម្រាប់ order ពិត។

វិធីទីពីរគឺ NOT EXISTS ជាមួយ subquery៖

SELECT c.name
FROM customers c
WHERE NOT EXISTS (
  SELECT 1
  FROM orders o
  WHERE o.customer_id = c.id
)
ORDER BY c.id;

វាត្រឡប់អតិថិជនពីរនាក់ដដែល។ អានវាថា៖ "អតិថិជនដែលគ្មាន order ណាមាន id របស់ពួកគេ។" SELECT 1 គ្រាន់តែជាទម្លាប់ ព្រោះ EXISTS ខ្វល់តែថាមានជួរត្រឡប់មកឬអត់ មិនមែនខ្វល់ថាអ្វីនៅក្នុងនោះទេ។

តើគួរប្រើមួយណា? ទាំងពីរត្រឹមត្រូវ ហើយ PostgreSQL ជាធម្មតាធ្វើផែនការដូចគ្នា។ មនុស្សជាច្រើនយល់ថា NOT EXISTS អានដូចសំណួរជាភាសាអង់គ្លេសជាង។ ប្រើមួយណាដែលក្រុមរបស់អ្នកចូលចិត្ត ប៉ុន្តែចៀសវាង NOT IN (SELECT ...) សម្រាប់ការងារនេះ។ ប្រសិនបើ subquery ត្រឡប់ NULL ម្តង NOT IN នឹងមិនត្រឡប់ជួរណាសោះ ជាការភ្ញាក់ផ្អើលអាក្រក់មកពីតក្កវិជ្ជាបីតម្លៃ (three-valued logic) ដែលអ្នកបានឃើញក្នុងជំពូកទី 5។

anti-join មានគ្រប់ទីកន្លែងក្នុងការងារពិត៖ ផលិតផលដែលមិនធ្លាប់លក់, អ្នកប្រើដែលមិនធ្លាប់ login, វិក្កយបត្រដែលគ្មានការបង់ប្រាក់។ សាកល្បងមួយនេះលើផលិតផល៖

SELECT p.name
FROM products p
LEFT JOIN order_items oi ON oi.product_id = p.id
WHERE oi.order_id IS NULL;
 name
------
(0 rows)

ជាមួយ seed data របស់យើង រាល់ផលិតផលត្រូវបានបញ្ជាទិញយ៉ាងហោចណាស់ម្តង ដូច្នេះលទ្ធផលទទេ។ លទ្ធផលទទេគឺជាចម្លើយត្រឹមត្រូវ មិនមែនជាកំហុសទេ។

6. RIGHT JOIN និង FULL JOIN

RIGHT JOIN គឺជារូបភាពក្នុងកញ្ចក់នៃ LEFT JOIN៖ វារក្សារាល់ជួរពី table ខាងស្តាំ។

SELECT p.name AS product, oi.order_id
FROM order_items oi
RIGHT JOIN products p ON p.id = oi.product_id
ORDER BY p.id, oi.order_id;

នេះរក្សារាល់ផលិតផល ទោះមិនធ្លាប់បញ្ជាទិញក៏ដោយ។ ជាមួយទិន្នន័យរបស់យើង រាល់ផលិតផលត្រូវបានបញ្ជាទិញ ដូច្នេះវាមើលទៅដូច inner join៖

       product       | order_id
---------------------+----------
 Wireless Mouse      |        1
 Wireless Mouse      |        4
 USB-C Cable         |        1
 Mechanical Keyboard |        2
 SQL Cookbook        |        3
 Clean Code          |        3
 Desk Lamp           |        5
 Coffee Mug          |        4
 Notebook Pack       |        4
(9 rows)

ក្នុងការអនុវត្តស្ទើរតែគ្មានអ្នកណាសរសេរ RIGHT JOIN ទេ។ right join ណាក៏អាចសរសេរឡើងវិញជា left join បានដោយប្តូរលំដាប់ table ហើយការអានពីឆ្វេងទៅស្តាំងាយស្រួលជាង។ អ្នកត្រូវស្គាល់វា មិនចាំបាច់ប្រើវាទេ។

FULL JOIN (full outer join) រក្សាជួរគ្មានគូពី ទាំងពីរ ខាង។ វាកម្រប្រើ ប៉ុន្តែមានប្រយោជន៍សម្រាប់ប្រៀបធៀបបញ្ជីពីរ៖ "អ្វីដែលមានតែក្នុង A, តែក្នុង B និងក្នុងទាំងពីរ?" តោះមើលវាជាមួយបញ្ជីតូចៗបណ្តោះអាសន្នពីរ ដែលបង្កើតភ្លាមៗដោយ VALUES៖

WITH a(x) AS (VALUES (1), (2), (3)),
     b(x) AS (VALUES (2), (3), (4))
SELECT a.x AS a_x, b.x AS b_x
FROM a
FULL JOIN b ON a.x = b.x
ORDER BY COALESCE(a.x, b.x);
 a_x | b_x
-----+-----
   1 |
   2 |   2
   3 |   3
     |   4
(4 rows)

ជួរ 1 មានតែក្នុង a ជួរ 4 មានតែក្នុង b ហើយ 2 និង 3 មានក្នុងទាំងពីរ។ (ផ្នែក WITH គឺជា CTE ជា query បណ្តោះអាសន្នដែលមានឈ្មោះ។ យើងនឹងរៀនវាឲ្យបានត្រឹមត្រូវក្នុងជំពូកបន្ទាប់។)

នេះគឺជាក្រុម join ទាំងមូលមួយភ្លែត៖

Joinរក្សា
INNER JOINតែគូដែលត្រូវគ្នា
LEFT JOINរាល់ជួរខាងឆ្វេង ជាមួយជួរខាងស្តាំដែលត្រូវគ្នា ឬ NULL
RIGHT JOINរាល់ជួរខាងស្តាំ ជាមួយជួរខាងឆ្វេងដែលត្រូវគ្នា ឬ NULL
FULL JOINរាល់ជួរពីទាំងពីរខាង
CROSS JOINរាល់ជួរខាងឆ្វេងផ្គូផ្គងជាមួយរាល់ជួរខាងស្តាំ

7. CROSS JOIN

CROSS JOIN គ្មាន clause ON ទេ។ វាផ្គូផ្គង រាល់ ជួរនៃ table មួយជាមួយ រាល់ ជួរនៃ table មួយទៀត។ ប្រសិនបើខាងឆ្វេងមាន 3 ជួរ ហើយខាងស្តាំមាន 4 អ្នកនឹងបាន 12។

SELECT cat.name AS category, s.status
FROM categories cat
CROSS JOIN (SELECT DISTINCT status FROM orders) s
ORDER BY cat.name, s.status;
  category   |  status
-------------+-----------
 Books       | cancelled
 Books       | paid
 Books       | pending
 Books       | shipped
 Electronics | cancelled
 Electronics | paid
 Electronics | pending
 Electronics | shipped
 Home        | cancelled
 Home        | paid
 Home        | pending
 Home        | shipped
(12 rows)

បីប្រភេទគុណបួនស្ថានភាពស្មើដប់ពីរបន្សំ។ នេះមានប្រយោជន៍សម្រាប់សាងសង់ "ក្រឡាចត្រង្គ" នៃលទ្ធភាពទាំងអស់ ឧទាហរណ៍រាល់ប្រភេទ និងស្ថានភាព ដើម្បីឲ្យរបាយការណ៍អាចបង្ហាញលេខសូន្យជំនួសឲ្យជួរដែលបាត់។

វាក៏ជារឿងព្រមានអំពី join ដោយចៃដន្យដែរ។ ប្រសិនបើអ្នកភ្លេចលក្ខខណ្ឌ ON ក្នុង comma join បែបចាស់ (FROM customers, orders) អ្នកនឹងបាន cross join ដោយស្ងៀមស្ងាត់៖ អតិថិជន 5 គុណ order 5 គឺ 25 ជួរគ្មានន័យ។ ជាមួយ table ធំពីរ វាអាចជារាប់លានជួរ និង terminal គាំង។ ប្រើ JOIN ... ON ច្បាស់លាស់ជានិច្ច។

8. Self Join

table អាច join ជាមួយ ខ្លួនឯង បាន។ អ្នកផ្តល់ alias ពីរផ្សេងគ្នា ហើយចាត់ទុកវាជាច្បាប់ចម្លងពីរ។ ការប្រើប្រាស់ធម្មជាតិគឺ "រកគូនៃជួរក្នុង table តែមួយដែលមានអ្វីមួយដូចគ្នា"។ តើអតិថិជនណាខ្លះរស់នៅក្នុងទីក្រុងតែមួយ?

SELECT a.name AS customer, b.name AS neighbour, a.city
FROM customers a
JOIN customers b
  ON a.city = b.city
 AND a.id < b.id;
  customer  | neighbour  |    city
------------+------------+------------
 Sokha Chan | Linda Vong | Phnom Penh
(1 row)

មានរឿងពីរត្រូវកត់សម្គាល់។ ទីមួយ alias a និង b ចាំបាច់ បើមិនដូច្នោះទេ PostgreSQL មិនអាចបែងចែកច្បាប់ចម្លងទាំងពីរបានទេ។ ទីពីរ a.id < b.id គឺជាល្បិចដើម្បីចៀសវាងលទ្ធផលរំខាន។ បើគ្មានវា អតិថិជនគ្រប់គ្នាផ្គូផ្គងនឹងខ្លួនឯង (Sokha ជាមួយ Sokha) ហើយគូពិតនីមួយៗលេចឡើងពីរដង (Sokha ជាមួយ Linda រួច Linda ជាមួយ Sokha)។ ការតម្រូវ a.id < b.id រក្សាគូនីមួយៗតែម្តង។

ចំណាំផងដែរថា Maly ដែលមាន city ជា NULL មិនត្រូវគ្នានឹងអ្នកណាទេ។ NULL = NULL មិនពិតទេ វាជាមិនស្គាល់ ដូច្នេះលក្ខខណ្ឌ join បរាជ័យ។

self join គឺជាវិធីដែលអ្នកធ្វើគំរូឋានានុក្រម ដូចជាបុគ្គលិក និងអ្នកគ្រប់គ្រងរបស់ពួកគេដែលរក្សាទុកក្នុង table តែមួយជាមួយ column manager_id។ ហាងរបស់យើងមិនត្រូវការវាទេ ប៉ុន្តែអ្នកនឹងជួបវា។

9. ការ Join Table បីឬបួន

សំណួរពិតជាធម្មតាគ្របដណ្តប់ច្រើនជាង table ពីរ។ អ្នកគ្រាន់តែបន្តតភ្ជាប់ join។ JOIN នីមួយៗយកលទ្ធផលរហូតមកដល់ពេលនេះ ហើយភ្ជាប់ table មួយទៀត។

"សម្រាប់ order ដែលបានបង់ប្រាក់នីមួយៗ បញ្ជីថាអ្នកណាទិញអ្វី ជាមួយប្រភេទ"៖

SELECT c.name AS customer,
       o.id AS order_id,
       p.name AS product,
       cat.name AS category,
       oi.quantity
FROM customers c
JOIN orders o       ON o.customer_id = c.id
JOIN order_items oi ON oi.order_id = o.id
JOIN products p     ON p.id = oi.product_id
JOIN categories cat ON cat.id = p.category_id
WHERE o.status = 'paid'
ORDER BY o.id, p.id;
  customer  | order_id |    product     |  category   | quantity
------------+----------+----------------+-------------+----------
 Sokha Chan |        1 | Wireless Mouse | Electronics |        1
 Sokha Chan |        1 | USB-C Cable    | Electronics |        2
 Linda Vong |        4 | Wireless Mouse | Electronics |        2
 Linda Vong |        4 | Coffee Mug     | Home        |        3
 Linda Vong |        4 | Notebook Pack  | Books       |        1
(5 rows)

ផ្លូវ table ប្រាំគឺជាហាងទាំងមូល៖ customer, order, line, product, category។ សូមមើលថា ON នីមួយៗតភ្ជាប់ table ថ្មីទៅនឹង table ដែលមានក្នុងខ្សែសង្វាក់រួចហើយយ៉ាងណា៖ foreign key នៅម្ខាង primary key នៅម្ខាងទៀត។ ភាពទៀងទាត់នោះគឺជាផលនៃការរចនា key ល្អពីជំពូកទី 6។

គន្លឹះសម្រាប់ join វែងៗ៖

  • សរសេរ JOIN មួយក្នុងមួយបន្ទាត់ ហើយតម្រឹមផ្នែក ON។ ភ្នែករបស់អ្នកនឹងអរគុណ។
  • សាងសង់វាម្តងមួយជំហាន។ ចាប់ផ្តើមជាមួយ table ពីរ ពិនិត្យលទ្ធផល បន្ថែម table បន្ទាប់ ហើយពិនិត្យម្តងទៀត។
  • លំដាប់នៃ JOIN កម្រប៉ះពាល់ដល់ភាពត្រឹមត្រូវជាមួយ inner join ណាស់។ planner របស់ PostgreSQL ជ្រើសលំដាប់ដែលមានប្រសិទ្ធភាពដោយខ្លួនឯង។
  • ពិនិត្យចំនួនជួរបន្ទាប់ពីជំហាននីមួយៗ។ ប្រសិនបើជំហានណាមួយគុណជួរដោយមិននឹកស្មានដល់ សូមមើលផ្នែកទី 11។

ការលាយក៏អនុញ្ញាតដែរ។ ប្រសិនបើអ្នកចង់បានអតិថិជនគ្រប់គ្នាទោះគ្មាន order ត្រូវធ្វើ join ទីមួយជា LEFT JOIN ហើយចាំថា join ក្រោយៗក្នុងខ្សែសង្វាក់ក៏ត្រូវជា LEFT JOIN ដែរ ប្រសិនបើអ្នកនៅតែចង់រក្សាអតិថិជនទាំងនោះ (inner join ក្រោយមកនឹងបោះជួរទទេចោលម្តងទៀត)។

10. ON ទល់នឹង USING

ពេល column ដែលត្រូវ join មាន ឈ្មោះដូចគ្នា ក្នុង table ទាំងពីរ អ្នកអាចប្រើ USING ជាអក្សរកាត់៖

-- with ON
SELECT * FROM orders o JOIN customers c ON c.id = o.customer_id;

USING ត្រូវការ ឈ្មោះ column ដូចគ្នា នៅទាំងពីរខាង ហើយវាបញ្ចូល column ទាំងពីរជា column លទ្ធផលតែមួយ។ ឧទាហរណ៍ ប្រសិនបើ order_items មាន column ឈ្មោះ id ដែលត្រូវនឹង orders.id អ្នកអាចសរសេរ JOIN order_items USING (id)។ ក្នុង shopdb ឈ្មោះខុសគ្នា (orders.id ទល់នឹង order_items.order_id) ដូច្នេះយើងប្រើ ON។

ត្រូវប្រយ័ត្ន៖ ក្នុង schema របស់យើង ទាំង orders និង customers មាន column ឈ្មោះ id ប៉ុន្តែវាមានន័យខុសគ្នា។ customers JOIN orders USING (id) នឹងជា SQL ត្រឹមត្រូវ ហើយនឹងផ្គូផ្គងអតិថិជន 1 ជាមួយ order 1, អតិថិជន 2 ជាមួយ order 2 ជាដើម ដែលជាលទ្ធផលគ្មានន័យ។ នោះហើយជាមូលហេតុដែលរចនាប័ទ្ម surrogate-key id បូក customer_id មានប្រយោជន៍៖ មានតែ column ដែលទាក់ទងគ្នាពិតប្រាកដទេដែលចែករំលែកឈ្មោះ។

ដំបូន្មានរបស់ខ្ញុំ៖ ចូលចិត្ត ON។ វាច្បាស់លាស់ គ្រប់គ្រងឈ្មោះ column និងលក្ខខណ្ឌណាក៏បាន (a.id < b.id) ហើយមិនអាចត្រូវបោកបញ្ឆោតដោយ column ដែលចៃដន្យមានឈ្មោះដូចគ្នា។ ប្រើ USING តែពេលអ្នកចូលចិត្តភាពខ្លីរបស់វា ហើយឈ្មោះនោះមានន័យដូចគ្នាពិតប្រាកដ។

11. កំហុសទី 1៖ ការគុណជួរ

join ផ្គូផ្គង រាល់ ជួរដែលត្រូវគ្នា។ ពេលម្ខាងមានការផ្គូផ្គងច្រើន ជួររបស់ម្ខាងទៀតត្រូវបានធ្វើម្តងទៀត។ នោះត្រឹមត្រូវ ប៉ុន្តែវាអាចធ្វើឲ្យអ្នកភ្ញាក់ផ្អើល។

table orders មាន 5 ជួរ។ Join វាជាមួយ line របស់វា ហើយរាប់៖

SELECT count(*)
FROM orders o
JOIN order_items oi ON oi.order_id = o.id;
 count
-------
     9
(1 row)

ប្រាំបួន មិនមែនប្រាំទេ។ order 1 មាន line ពីរ ដូច្នេះឥឡូវវាលេចឡើងពីរដង។ ប្រសិនបើអ្នកបន្ទាប់មកបូកតម្លៃកម្រិត order ដូចជាថ្លៃដឹកជញ្ជូនដែលរក្សាទុកលើ orders អ្នកនឹងរាប់វាម្តងក្នុងមួយ line ហើយធ្វើឲ្យសរុបខ្ពស់ពេក។ ប្រសិនបើអ្នករាប់ order បន្ទាប់ពី join នេះ អ្នកនឹងបាន 9 ជំនួសឲ្យ 5។

ចាំបញ្ជីពិនិត្យនេះពេលណាលេខមើលទៅធំពេកបន្ទាប់ពី join៖

  • តើ join ណាក្នុងខ្សែសង្វាក់ជា one-to-many?
  • តើខ្ញុំកំពុងរាប់ ឬបូក column ដែលជារបស់ផ្នែក "one" ឬទេ?
  • តើខ្ញុំគួរ aggregate មុន join ឬប្រើ COUNT(DISTINCT ...)?

ជំពូកបន្ទាប់ អំពី aggregation បង្ហាញពីរបៀបរាប់ឲ្យត្រឹមត្រូវកាត់តាម join។ សម្រាប់ពេលនេះ មេរៀនគឺ៖ បន្ទាប់ពី join នីមួយៗ សួរថា "តើវាគួរមានប៉ុន្មានជួរ?" ហើយដំណើរការ SELECT count(*) ដើម្បីពិនិត្យ។

បញ្ហាផ្ទុយគឺ ការបាត់ជួរ៖ inner join ទម្លាក់ជួរដែលគ្មានគូដោយស្ងៀមស្ងាត់។ ប្រសិនបើរបាយការណ៍របស់អ្នកបាត់អតិថិជន JOIN ដែលគួរតែជា LEFT JOIN គឺជាជនសង្ស័យដំបូង។

12. កំហុសទី 2៖ ការ Filter LEFT JOIN ក្នុង WHERE

នេះគឺជាកំហុស LEFT JOIN ទូទៅបំផុត។ ឧបមាថាអ្នកចង់បានអតិថិជនទាំងអស់ ហើយសម្រាប់ម្នាក់ៗ យកតែ order ដែល បានបង់ប្រាក់ របស់ពួកគេ។ អ្នកអាចសរសេរ៖

SELECT c.name, o.id AS order_id, o.status
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'paid'
ORDER BY c.id;
    name    | order_id | status
------------+----------+--------
 Sokha Chan |        1 | paid
 Linda Vong |        4 | paid
(2 rows)

Dara, Vuthy និង Maly បាត់ទៅហើយ។ ហេតុអ្វី? WHERE ដំណើរការ បន្ទាប់ពី join។ សម្រាប់ Vuthy o.status ដែលបាន join គឺ NULL ហើយ NULL = 'paid' មិនពិតទេ ដូច្នេះជួរត្រូវបានបោះចោល។ លក្ខខណ្ឌ WHERE បានប្តូរ left join ទៅជា inner join ហើយអ្នកបានចម្លើយខុសដោយគ្មានកំហុសណាមួយ។

ដំណោះស្រាយគឺផ្លាស់លក្ខខណ្ឌទៅក្នុង clause ON ដែលវាសម្រេចថាជួរណាត្រូវបានចាត់ទុកជាការផ្គូផ្គង ជំនួសឲ្យជួរលទ្ធផលណាដែលនៅរស់៖

SELECT c.name, o.id AS order_id, o.status
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id
 AND o.status = 'paid'
ORDER BY c.id;
    name    | order_id | status
------------+----------+--------
 Sokha Chan |        1 | paid
 Dara Kim   |          |
 Linda Vong |        4 | paid
 Vuthy Sok  |          |
 Maly Ros   |          |
(5 rows)

ឥឡូវអតិថិជនទាំងប្រាំលេចឡើង។ Dara មាន order ប៉ុន្តែគ្មានមួយណាបានបង់ប្រាក់ ដូច្នេះ column order របស់នាងជា NULL។ order 2 ដែលបានដឹកជញ្ជូនរបស់ Sokha មិនត្រូវគ្នាទេ ដូច្នេះវាមិនត្រូវបានបង្ហាញ។

ច្បាប់៖ សម្រាប់ table ខាងស្តាំ នៃ LEFT JOIN ដាក់ filter របស់វាក្នុង ON។ filter លើ table ខាងឆ្វេង អាចនៅក្នុង WHERE បានដោយសុវត្ថិភាព។ (មានករណីលើកលែងដោយចេតនាមួយ គឺ anti-join ពីផ្នែកទី 5 ដែល WHERE o.id IS NULL គឺជាគោលបំណងពិតប្រាកដ។)

រក្សាទុកអ្វីៗទាំងអស់ដែលអ្នកបានសាកល្បងទៅក្នុង shopdb/queries/07_joins.sql ដើម្បីឲ្យអ្នកអាចដំណើរការវាម្តងទៀត។

13. សាកល្បងដោយខ្លួនឯង

ដំណើរការទាំងនេះលើ shopdb។ ពិនិត្យចម្លើយនីមួយៗដោយគិតអំពីទិន្នន័យជាមុនសិន បន្ទាប់មកដំណើរការ query។

  1. បញ្ជីឈ្មោះផលិតផលនីមួយៗជាមួយឈ្មោះប្រភេទរបស់វា (inner join រវាង products និង categories) តម្រៀបតាមប្រភេទ រួចតាមឈ្មោះផលិតផល។ តើអ្នកបានប៉ុន្មានជួរ? ហេតុអ្វីបានជាវាស្មើនឹងចំនួនផលិតផល?
  2. បង្ហាញ order គ្រប់ទាំងអស់ជាមួយឈ្មោះ និងទីក្រុងរបស់អតិថិជន។ បន្ទាប់មកកែ query ឲ្យបង្ហាញតែ order ដែលដាក់ដោយអតិថិជនមកពីភ្នំពេញ (Phnom Penh)។ តើ order ណាខ្លះនៅសល់?
  3. សរសេរ query LEFT JOIN ដែលបញ្ជីផលិតផលនីមួយៗជាមួយ id របស់ order ដែលវាលេចឡើងក្នុង (NULL ពេលមិនធ្លាប់បញ្ជាទិញ)។ បន្ទាប់មកសរសេរវាឡើងវិញជា anti-join ដើម្បីរកផលិតផលដែលមិនធ្លាប់បញ្ជាទិញ។ តើអ្នកសង្ឃឹមថាបានអ្វី ហើយអ្នកបានអ្វី?
  4. បញ្ជី line របស់ order 3 ជាមួយឈ្មោះផលិតផល, quantity, unit_price និង line_total ដែលគណនា (quantity * unit_price)។ បន្ថែម join ទីប្រាំដើម្បីបញ្ចូលឈ្មោះអតិថិជន។
  5. ប្រើ self join លើ products ដើម្បីរកគូផលិតផលទាំងអស់ក្នុងប្រភេទតែមួយដែលផលិតផលទីមួយថោកជាងទីពីរ។ តើមានប៉ុន្មានគូសម្រាប់ Electronics? (ជំនួយ៖ ផលិតផលបី ដូច្នេះគិតថាមានប៉ុន្មានគូពីបី។)
  6. ទាយចំនួនជួរនៃ customers CROSS JOIN categories បន្ទាប់មកដំណើរការ SELECT count(*) លើវាដើម្បីពិនិត្យ។ ជាចុងក្រោយ សរសេរ query "order ដែលបានបង់ប្រាក់តែប៉ុណ្ណោះ" ពីផ្នែកទី 12 ឡើងវិញ ដើម្បីឲ្យវាបង្ហាញជួររបស់ Maly Ros ផងដែរ ហើយពន្យល់ក្នុងប្រយោគតែមួយថា ហេតុអ្វីបានជា filter WHERE លើ o.status មិនអាចធ្វើបែបនោះបាន។

ទៅទីណាបន្ត។ ឥឡូវអ្នកអាចអាន និងសរសេរ query កាត់តាម table ទាំងអស់របស់ហាង។ សំណួរបន្ទាប់ដែលធម្មជាតិគឺ "ប៉ុន្មាន?" និង "មានចំនួនប៉ុន្មាន?" ក្នុង Aggregation និង Grouping អ្នកនឹងរៀន COUNT, SUM, AVG, GROUP BY និង HAVING ដើម្បីបំប្លែងជួរដែលបាន join ទាំងអស់នេះទៅជាចំណូលក្នុងមួយអតិថិជន ការលក់ក្នុងមួយប្រភេទ និង order ក្នុងមួយខែ។

ទិញកាហ្វេជូនខ្ញុំ

ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!