Artıq bilirsən ki, cədvəlləri JOIN ilə birləşdirmək olur. Amma real həyatda sadəcə açarların uyğun gəlməsi bəzən kifayət etmir. Tez-tez belə bir məsələ çıxır: məlumatları yalnız əlavə bir kriteriyaya uyğun gələndə birləşdirmək — məsələn, yalnız aktiv qeydlər, yalnız cari ilin məlumatları və ya yalnız tamamlanmış sifarişlər.
Və bax, burada ON konstruksiyasını AND ilə genişləndirmək işə yarayır.
JOIN ... ON-da əlavə şərtlər birləşmədə hansı sətrlərin iştirak edəcəyinə tam nəzarət etməyə imkan verir, hələ SQL nəticəni qurmağa başlamamışdan əvvəl. Bu sorğunu belə edir:
- Daha sürətli (daha az sətir
JOIN-dan keçir), - Daha dəqiq (filtrasiya birləşmə mərhələsində baş verir),
- Daha proqnozlaşdırıla bilən
LEFT JOINilə işləyəndə (WHERE-da filtrasiyadan fərqli olaraq).
Nümunə: Yalnız kurslara aktiv yazılanlar
Tutaq ki, enrollments cədvəlində tələbənin iştirak statusu var: active, dropped, pending.
students cədvəli:
| id | name |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
enrollments cədvəlini yeniləyək:
| student_id | course_id | status |
|---|---|---|
| 1 | 101 | active |
| 1 | 103 | active |
| 2 | 102 | dropped |
| 3 | 101 | active |
courses cədvəli:
| id | name |
|---|---|
| 101 | Mathematics |
| 102 | Physics |
| 103 | Computer Science |
İndi istəyirik ki, yalnız aktiv kursları olan tələbələri əldə edək:
SELECT
students.name AS student_name,
courses.name AS course_name
FROM students
INNER JOIN enrollments
ON students.id = enrollments.student_id
AND enrollments.status = 'active'
INNER JOIN courses
ON enrollments.course_id = courses.id;
Nəticə:
| student_name | course_name |
|---|---|
| Otto Song | Mathematics |
| Otto Song | Computer Science |
| Alex Lin | Mathematics |
Burada AND enrollments.status = 'active' ON-un içində əlavə etdik ki, birləşmə yalnız aktiv qeydlərə görə baş versin, nəticədən sonra filtrasiya olmasın.
Niyə WHERE yox?
Belə də yazmaq olardı:
...
WHERE enrollments.status = 'active'
Amma bu LEFT JOIN-da fərqli davranır. WHERE-da filtrasiya uyğunluq olmayan sətrləri (NULL) silir və nəticədə LEFT JOIN-ı INNER JOIN-a çevirir.
Amma AND enrollments.status = 'active' şərti ON-un içində birləşən sətrləri dərhal məhdudlaşdırır — birləşməyə ümumiyyətlə hansı sətrlərin düşəcəyinə nəzarət edir, sadəcə nəticəni sonra filtrasiya etmir.
Bu yanaşma xüsusilə vacibdir, əgər istəyirsənsə ki, bir cədvəldə olan sətrlər qalsın, hətta digər cədvəldə uyğun dəyər olmasa belə (bu, hesabat və analitikada tez-tez olur).
ON ... AND ... istifadəsinə başqa nümunələr
students cədvəli:
| id | name |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
enrollments cədvəli:
| student_id | course_id | status | enrolled_at |
|---|---|---|---|
| 1 | 101 | active | 2025-02-01 |
| 1 | 103 | active | 2025-03-05 |
| 2 | 102 | dropped | 2024-05-15 |
| 3 | 101 | active | 2025-03-12 |
courses cədvəli:
| id | name |
|---|---|
| 101 | Math |
| 102 | Physics |
| 103 | CS |
Nümunə: yalnız cari ilin kursları
SELECT
students.name,
courses.name,
enrollments.enrolled_at
FROM students
JOIN enrollments
ON students.id = enrollments.student_id
AND EXTRACT(YEAR FROM enrollments.enrolled_at) = EXTRACT(YEAR FROM CURRENT_DATE)
JOIN courses
ON enrollments.course_id = courses.id;
Burada yalnız cari ilə aid olan qeydləri birləşdiririk.
| name | name | enrolled_at |
|---|---|---|
| Otto Song | Math | 2025-02-01 |
| Otto Song | CS | 2025-03-05 |
| Alex Lin | Math | 2025-03-12 |
Nümunə: dəyərə görə istisna
JOIN enrollments
ON students.id = enrollments.student_id
AND enrollments.status != 'dropped'
Çıxarılmış tələbələri birləşmə mərhələsində istisna edirik, nəticədən sonra yox.
| name | name |
|---|---|
| Otto Song | Math |
| Otto Song | CS |
| Alex Lin | Math |
Şərt ON-un içində olanda, PostgreSQL birləşmə planını optimallaşdıra və daha az sətir işləyə bilər. Bu, böyük həcmli məlumatlarda xüsusilə vacibdir. Daxili filtrasiya JOIN-dan sonra "təmizləmə"dən daha effektivdir.
JOIN ON — yalnız açarlar üçün deyil
Çoxları düşünür ki, ON — sadəcə id = id-dir. Əslində ora əlavə etmək olar:
- Logical operatorlar:
AND,OR,NOT - Müqayisələr:
>,<,<>,BETWEEN,IN - Expressions:
EXTRACT,DATE_TRUNC,COALESCE,NULLIF
Hamısını birləşdiririk
students cədvəli:
| id | name |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
faculties cədvəli:
| id | name | |
|---|---|---|
| 10 | Engineering | |
| 20 | Natural Sciences | |
| 30 | ← ad yoxdur (NULL) |
courses cədvəli:
| id | name | teacher | faculty_id |
|---|---|---|---|
| 101 | Math | Liam Park | 10 |
| 102 | Physics | Chloe Zhang | 20 |
| 103 | CS | Noah Kim | 10 |
| 104 | PE | Ava Chen | 30 |
enrollments cədvəli:
| student_id | course_id | status |
|---|---|---|
| 1 | 101 | active |
| 1 | 103 | active |
| 2 | 102 | dropped |
| 3 | 101 | active |
| 3 | 104 | active |
SELECT
s.name AS student_name,
c.name AS course_name,
f.name AS faculty_name
FROM students s
JOIN enrollments e
ON s.id = e.student_id
AND e.status = 'active'
JOIN courses c
ON e.course_id = c.id
AND c.name != 'Fizkultura'
JOIN faculties f
ON c.faculty_id = f.id
AND f.name IS NOT NULL;
Burada eyni anda filtrasiya edirik:
- Aktiv qeydlərə,
- "Fizkultura"dan başqa kurslara,
- Adı olan fakültələrə.
Sorğunun nəticəsi:
| student_name | course_name | faculty_name |
|---|---|---|
| Otto Song | Math | Engineering |
| Otto Song | CS | Engineering |
| Alex Lin | Math | Engineering |
Ümid edirəm bu leksiya xoşuna gəldi. Sorğularda bir neçə JOIN və filtr tez-tez istifadə edəcəksən. Demək olar ki, həmişə :)
GO TO FULL VERSION