Məzmuna keç
Educora
Orta18 dəq9 / 22

Alt sorğular

Sorğunun içində sorğu yaz: WHERE, SELECT və FROM hissələrində alt sorğular, IN, EXISTS, əlaqəli alt sorğular və WITH ifadəsi.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • Tək qiymət və siyahı qaytaran alt sorğular yazmaq
  • EXISTS və əlaqəli alt sorğulardan istifadə etmək
  • FROM-da alt sorğu və WITH ilə mürəkkəb sorğunu hissələrə bölmək
  • NOT IN və NULL tələsindən qaçmaq

«Hansı məhsullar orta qiymətdən bahadır?» Bu sual iki addımdır: əvvəlcə orta qiyməti tapmaq (293,56), sonra onunla müqayisə etmək. Ədədi əllə sorğuya yazmaq olar, amma sabah qiymətlər dəyişəndə sorğu köhnələcək. Daha yaxşı yol — hər iki addımı bir sorğuda etmək. Bunun üçün alt sorğudan istifadə edirik.

WHERE-də alt sorğu

Tərif
Alt sorğu

Başqa sorğunun içində mötərizədə yazılmış SELECT sorğusu. Onun nəticəsi xarici sorğuda qiymət, siyahı və ya cədvəl kimi istifadə olunur.

SQL
SELECT name, price
FROM products
WHERE price > (SELECT AVG(price) FROM products)
ORDER BY price DESC;
▸ Gözlənilən nəticə
name | price
Laptop | 1450
Smartphone | 899.99
Monitor | 310

Əvvəlcə daxili sorğu icra olunur və bir ədəd qaytarır, sonra xarici sorğu onu adi ədəd kimi işlədir. Belə alt sorğu skalyar adlanır: o, düz bir sətir və bir sütun qaytarmalıdır. Keçən dərslərdəki «ən bahalı məhsulun adı» sualının universal həlli də budur:

SQL
SELECT name, price
FROM products
WHERE price = (SELECT MAX(price) FROM products);
▸ Gözlənilən nəticə
name | price
Laptop | 1450

IN və NOT IN ilə alt sorğu

Alt sorğu bir sütunda çoxlu sətir qaytarırsa, onu IN-in siyahısı kimi işlətmək olar. Fizika kurslarına yazılan şagirdləri tapaq. Alt sorğular bir-birinin içinə də yerləşdirilə bilər: ən daxili sorğu fizika kurslarının nömrələrini, ortadakı həmin kurslara yazılan şagirdlərin nömrələrini qaytarır.

SQL
SELECT first_name, last_name
FROM students
WHERE id IN (
  SELECT student_id
  FROM enrollments
  WHERE course_id IN (SELECT id FROM courses WHERE subject = 'Physics')
)
ORDER BY id;
▸ Gözlənilən nəticə
first_name | last_name
Murad | Əliyev
Elvin | Quliyev
Rəşad | Kərimov
Fidan | Cəfərova
SQL
SELECT name, category
FROM products
WHERE id NOT IN (SELECT product_id FROM orders)
ORDER BY id;
▸ Gözlənilən nəticə
name | category
Monitor | Electronics
Heç vaxt sifariş olunmayan məhsul — keçən dərsdəki LEFT JOIN ... IS NULL ilə eyni nəticə.
SQL
SELECT COUNT(*) AS found
FROM products
WHERE id NOT IN (1, 2, NULL);
▸ Gözlənilən nəticə
found
0
NULL-u siyahıdan sil və yenidən icra et — nəticə 8 olacaq.

EXISTS və əlaqəli alt sorğular

Əlaqəli (correlated) alt sorğu xarici sorğunun sütununa istinad edir, məsələn, o.customer_id = c.id. Məntiqi olaraq o, xarici sorğunun hər sətri üçün yenidən hesablanır. EXISTS (...) alt sorğu ən azı bir sətir qaytaranda doğrudur — sətirlərin nə olduğu vacib deyil, ona görə içəridə adətən SELECT 1 yazılır.

SQL
SELECT c.name, c.country
FROM customers AS c
WHERE EXISTS (
  SELECT 1
  FROM orders AS o
  JOIN products AS p ON p.id = o.product_id
  WHERE o.customer_id = c.id
    AND p.category = 'Electronics'
)
ORDER BY c.id;
▸ Gözlənilən nəticə
name | country
Anar Mustafayev | Azerbaijan
Lalə Əhmədova | Azerbaijan
Emre Yılmaz | Türkiye
Zəhra Hüseynli | Azerbaijan
Ən azı bir dəfə elektronika alan müştərilər.

Əlaqəli alt sorğu SELECT hissəsində də ola bilər — onda o, hər sətir üçün bir qiymət hesablayır. Aşağıda 10-cu sinif şagirdlərinin neçə kursa yazıldığını və ən yüksək balını görürük.

SQL
SELECT s.first_name,
       (SELECT COUNT(*)   FROM enrollments AS e WHERE e.student_id = s.id) AS courses,
       (SELECT MAX(score) FROM enrollments AS e WHERE e.student_id = s.id) AS best
FROM students AS s
WHERE s.grade = 10
ORDER BY s.id;
▸ Gözlənilən nəticə
first_name | courses | best
Murad | 2 | 81
Rəşad | 2 | 99
Səbinə | 2 | 88
Nümunə tapşırıq

Hansı yazılışlarda bal həmin kursun orta balından yüksəkdir?

Həllini göstər
Hər kursun öz ortası var, ona görə alt sorğu xarici sətrin kursunu bilməlidir.
Eyni cədvəli iki dəfə işlədirik və ləqəblərlə ayırırıq: xarici e, daxili e2.
Şərt: e.score > (SELECT AVG(e2.score) FROM enrollments AS e2 WHERE e2.course_id = e.course_id).
Hər kursdan ortadan yuxarı olan yazılışlar qalır — cəmi 9 sətir.
SQL
SELECT e.student_id, e.course_id, e.score
FROM enrollments AS e
WHERE e.score > (
  SELECT AVG(e2.score)
  FROM enrollments AS e2
  WHERE e2.course_id = e.course_id
)
ORDER BY e.course_id, e.score DESC;
▸ Gözlənilən nəticə
student_id | course_id | score
11 | 1 | 97
1 | 1 | 92
3 | 2 | 95
11 | 3 | 94
2 | 3 | 81
4 | 4 | 72
5 | 5 | 93
6 | 6 | 99
3 | 7 | 90

FROM-da alt sorğu və WITH

Alt sorğunun nəticəsi cədvəldir, ona görə onu FROM-da da yazmaq olar — bu, müvəqqəti cədvəl kimi işləyir. Əksər VBİS-lər belə alt sorğuya ləqəb verməyi tələb edir (AS t). Aşağıda əvvəlcə hər kursun ortasını tapırıq, sonra bu ortaların ortasını və ən yaxşısını.

SQL
SELECT ROUND(AVG(avg_score), 1) AS avg_of_courses,
       ROUND(MAX(avg_score), 1) AS best_course
FROM (
  SELECT course_id, AVG(score) AS avg_score
  FROM enrollments
  GROUP BY course_id
) AS t;
▸ Gözlənilən nəticə
avg_of_courses | best_course
82 | 92.7

Alt sorğular iç-içə çoxaldıqca sorğunu oxumaq çətinləşir. WITH ifadəsi (CTE — ümumi cədvəl ifadəsi) alt sorğuya əvvəlcədən ad verməyə və sonra onu adi cədvəl kimi işlətməyə imkan verir. WITH SQLite, PostgreSQL, SQL Server və MySQL 8.0-dan etibarən dəstəklənir.

SQL
WITH course_avg AS (
  SELECT course_id, ROUND(AVG(score), 1) AS avg_score
  FROM enrollments
  GROUP BY course_id
)
SELECT c.title, ca.avg_score
FROM course_avg AS ca
JOIN courses AS c ON c.id = ca.course_id
WHERE ca.avg_score > 85
ORDER BY ca.avg_score DESC;
▸ Gözlənilən nəticə
title | avg_score
Python Basics | 92.7
World History | 90.5
Algebra | 87.3
Tapşırıq

Yaşı bütün şagirdlərin orta yaşından böyük olan şagirdlərin adını və yaşını göstər. Yaşa görə azalan, eyni yaşda olanları ada görə artan sırada düz. Orta yaşı əllə yazma — alt sorğu ilə hesabla.

Tapşırıq · SQL
SELECT first_name, age
FROM students
WHERE age > ( /* average age here */ )
ORDER BY age DESC, first_name;
▸ Gözlənilən nəticə
first_name | age
Elvin | 17
Fidan | 17
Tural | 17
Murad | 16
Rəşad | 16
Səbinə | 16
Tapşırıq

Türkiyədən olan müştərilərin (country = 'Türkiye') sifariş etdiyi məhsulların adlarını göstər. JOIN işlətmə — iç-içə IN alt sorğularından istifadə et. Nəticəni ada görə düz.

Tapşırıq · SQL
SELECT name
FROM products
WHERE id IN (
  -- product ids from the orders of Turkish customers
)
ORDER BY name;
▸ Gözlənilən nəticə
name
Chess set
Pen set
Smartphone

Əsas fikirlər

  • Alt sorğu mötərizədə yazılmış SELECT-dir; nəticəsi qiymət, siyahı və ya cədvəl kimi işlədilir.
  • Skalyar alt sorğu düz bir qiymət qaytarır və =, > kimi operatorlarla müqayisə olunur.
  • IN (SELECT ...) siyahı ilə işləyir; NOT IN siyahıda NULL olanda heç nə qaytarmır.
  • Əlaqəli alt sorğu xarici sətrə istinad edir; EXISTS ən azı bir sətrin olub-olmadığını yoxlayır.
  • FROM-dakı alt sorğuya ləqəb ver; mürəkkəb sorğuları WITH ilə hissələrə böl.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
Alt sorğu nədir?