CodeGym /Kurslar /SQL SELF /SELECT içində subquery-lərdən istifadə

SELECT içində subquery-lərdən istifadə

SQL SELF
Səviyyə , Dərs
Mövcuddur

Gəlin bir daha SELECT içində subquery-lər mövzusuna qayıdaq. Xüsusilə də, daxili sorğunun xarici sorğunun datalarına istinad edə bilməsi məsələsinə fokuslanaq. Elə bil hər şey sadədir, amma tam da belə deyil. Gəlin bu mövzuya bir az da dərindən baxaq...

SELECT içində subquery-lər əlavə sütunlar əlavə etməyə imkan verir, hansı ki, hesablanmış dəyərlər və ya başqa qeydlərdən və ya cədvəllərdən asılı olan datalardır. Məsələn, tələbələrin siyahısını onların orta balı, qeydiyyatdan keçdikləri kursların sayı və ya qrupdakı cari maksimum bal ilə çıxara bilərsən. Bu, datanı "yolda" analiz etmək lazım olanda, əvvəlcədən emal etmədən pivot sütunlar yaratmaq üçün faydalıdır.

SELECT içində subquery-lərin əsasları

Nümunələrə keçməzdən əvvəl, gəlin ümumi sintaksisi aydınlaşdıraq. SELECT içində subquery-lər belə görünür:

SELECT column1,
       column2,
       (SELECT aggregasiya_veya_shert FROM diger_cedvel WHERE shert) AS yeni_sutun_adi
FROM esas_cedvel;

Diqqət elə ki, subquery bir dəyər qaytarır və bu nəticə setində yeni sütun kimi çıxır. Burada shert esas_cedvel-in sütunlarına istinad edə bilər.

Nümunə 1: Tələbənin orta balını əlavə etmək

Gəlin sadə və faydalı bir sorğu ilə başlayaq: bizdə students cədvəli və tələbələrin qiymətlərinin saxlandığı grades cədvəli var.

students cədvəli:

id name
1 Alex Lin
2 Anna Song
3 Dan Seth

grades cədvəli:

student_id grade
1 90
1 85
2 76
3 88
3 92

İndi tələbələrin adları və orta qiymətləri ilə siyahısını almaq istəyirik. Bunun üçün SELECT içində subquery istifadə edirik:

SELECT
    s.id,
    s.name,
    (SELECT AVG(g.grade) 
     FROM grades g 
     WHERE g.student_id = s.id) AS average_grade
FROM students s;

Nəticə:

id name average_grade
1 Alex Lin 87.5
2 Anna Song 76.0
3 Dan Seth 90.0

Burada subquery (SELECT AVG(g.grade) FROM grades g WHERE g.student_id = s.id) hər tələbə üçün orta qiyməti hesablayır. O, students cədvəlindən hər sətrə bir dəyər qaytarır və bu, JOIN və ya əvvəlcədən VIEW yaratmaq istəmədikdə çox rahatdır.

Nümunə 2: Hər tələbə üçün kursların sayını hesablamaq

İndi tələbələr haqqında əlavə məlumat əlavə edək: onlar neçə kursa gedirlər. Bunun üçün əlavə cədvəllərimiz var:

enrollments cədvəli:

student_id course_id
1 101
1 102
2 101

Tələbələrin kurs sayı ilə siyahısını çıxarırıq:

SELECT
    s.id,
    s.name,
    (SELECT COUNT(*)
     FROM enrollments e
     WHERE e.student_id = s.id) AS course_count -- students cədvəlinə istinad
FROM students s;

Nəticə:

id name course_count
1 Alex Lin 2
2 Anna Song 1
3 Dan Seth 0

Subquery (SELECT COUNT(*) FROM enrollments e WHERE e.student_id = s.id) hər tələbə üçün enrollments cədvəlindəki qeydlərin sayını hesablayır.

Subquery-lərdə datanın aggregasiyası

Çox vaxt SELECT içində subquery-lər aggregasiya olunmuş datanı hesablamaq üçün istifadə olunur. AVG, SUM, COUNT, MAX, MIN kimi funksiyalar başqa sorğuların içində datanı birbaşa emal etməyə imkan verir.

Nümunə 3: Tələbənin ümumi balı

Gəlin hər tələbə üçün ümumi bal əlavə edək. Bunun üçün grades cədvəlindəki bütün qiymətlərin cəmini hesablayan subquery istifadə edirik:

SELECT
    s.id,
    s.name,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Nəticə:

id name total_grade
1 Alex Lin 175
2 Anna Song 76
3 Dan Seth 180

Bu subquery (SELECT SUM(g.grade) FROM grades g WHERE g.student_id = s.id) hər tələbənin qiymətlərini toplayır. Əgər tələbənin qiyməti yoxdursa, nəticə NULL olacaq, çünki SUM heç bir dəyər olmadıqda NULL qaytarır.

Məhdudiyyətlər və tövsiyələr

  1. Performans. SELECT içində subquery-lər əsas cədvəldəki hər sətr üçün ayrıca işləyir. Böyük dataset-lərdə bu, ciddi gecikmələrə səbəb ola bilər. Əgər mümkündürsə, onları JOIN ilə əvəz et və ya əvvəlcədən aggregasiya olunmuş data istifadə et. Məsələn:
SELECT
    s.id,
    s.name,
    g.total_grade
FROM students s
LEFT JOIN (
    SELECT student_id, SUM(grade) AS total_grade
    FROM grades
    GROUP BY student_id
) g ON s.id = g.student_id;

Bu JOIN yanaşması daha optimaldır, çünki qruplaşdırma və hesablama bir dəfə aparılır.

2. NULL ilə bağlı problemlər.

Əgər subquery-də data yoxdursa, nəticə NULL olacaq. Bu, bəzən gözlənilməz ola bilər. Nümunə:

SELECT
    s.id,
    s.name,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Əgər tələbənin grades cədvəlində heç bir qeydi yoxdursa, total_grade nəticəsi NULL olacaq. NULL-u 0 ilə əvəz etmək üçün COALESCE funksiyasından istifadə et:

SELECT
    s.id,
    s.name,
    COALESCE((SELECT SUM(g.grade)
              FROM grades g
              WHERE g.student_id = s.id), 0) AS total_grade
FROM students s;

Bəli, burada COALESCE funksiyasının ilk parametrinə

(
    SELECT SUM(g.grade)
    FROM grades g
    WHERE g.student_id = s.id
)

SELECT içində subquery-lərin optimizasiyası

Artıq hesablama və performans problemlərindən qaçmaq üçün:

  1. Subquery-lərdə istifadə olunan sütunlarda index-lərdən istifadə et. Məsələn, grades cədvəlində student_id üçün index performansı artıracaq.
  2. Əgər mümkündürsə, subquery-ləri əvvəlcədən aggregasiya olunmuş data və JOIN ilə əvəz et.
  3. Subquery-lərin işlədiyi datanın həcmini WHERE ilə filtrasiya edərək məhdudlaşdır.

Son nümunə: subquery-lərin birləşdirilməsi

Gəlin bütün bildiklərimizi birləşdirib, tələbənin adını, orta balını, kurs sayını və ümumi balını çıxaran sorğu yazaq:

SELECT
    s.id,
    s.name,
    (SELECT AVG(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS average_grade,
    (SELECT COUNT(*) 
     FROM enrollments e 
     WHERE e.student_id = s.id) AS course_count,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Bu sorğu subquery-lərin gücü ilə tələbənin tam profilini qaytarır. Orta və ümumi balı, eləcə də qeydiyyatdan keçdiyi kursların sayını görürük. Belə bir konstruktor, ayrıca VIEW və ya JOIN-lar yaratmadan aggregasiya olunmuş məlumatı tez almaq üçün əla üsuldur.

id name average_grade course_count total_grade
1 Alex Lin 87.5 2 175
2 Anna Song 76.0 1 76
3 Dan Seth 90.0 0 180
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION