Operasi himpunan bekerja pada hasil dua subquery yang union-compatible:
-- course yang berjalan di Fall 2017 ATAU Spring 2018(select course_id from section where semester = 'Fall' and year = 2017)union(select course_id from section where semester = 'Spring' and year = 2018);-- course yang berjalan di Fall 2017 DAN Spring 2018(... ) intersect (... );-- course yang berjalan di Fall 2017 TAPI TIDAK di Spring 2018(... ) except (... );
Untuk mempertahankan semua duplikat, gunakan union all, intersect all, except all.
Null Values
Tuple boleh punya nilai null untuk sebagian atributnya. null menandakan nilai yang tidak diketahui atau tidak ada.
Hasil ekspresi aritmetika apa pun yang melibatkan null adalah null. Contoh: 5 + null → null.
Predikat is null memeriksa nilai null; is not null kebalikannya:
select name from instructor where salary is null;
SQL memperlakukan hasil perbandingan apa pun yang melibatkan null sebagai unknown (kecuali is null / is not null). Contoh: 5 < null, null <> null, null = null → semuanya unknown.
Logika Tiga-Nilai
Karena ada nilai unknown, operasi Boolean diperluas:
Operasi
Hasil
true and unknown
unknown
false and unknown
false
unknown and unknown
unknown
true or unknown
true
false or unknown
unknown
unknown or unknown
unknown
Hasil predikat klausa where diperlakukan sebagai false jika ia bernilai unknown — baris tersebut tidak masuk hasil.
flowchart TD
A["Ekspresi melibatkan null"] --> B{"Jenis?"}
B -->|"Aritmetika: 5 + null"| C["Hasil = null"]
B -->|"Perbandingan: 5 = null / null = null"| D["Hasil = unknown"]
B -->|"is null / is not null"| E["Hasil = true atau false (pasti)"]
D --> F["di WHERE: unknown diperlakukan sebagai false<br/>maka baris dibuang"]
Aggregate Functions
Fungsi agregat beroperasi pada multiset nilai sebuah kolom dan mengembalikan satu nilai:
Fungsi
Hasil
avg
rata-rata
min
nilai minimum
max
nilai maksimum
sum
jumlah nilai
count
banyaknya nilai
select avg(salary) from instructor where dept_name = 'Comp. Sci.';select count(distinct ID)from teacheswhere semester = 'Spring' and year = 2018;select count(*) from course;
Catatan: count(*) menghitung baris (termasuk yang semua kolomnya null); count(A) menghitung baris dengan Abukan null. sum/avg juga mengabaikan null.
Group By
group by mengelompokkan tuple lalu menerapkan agregat per grup:
select dept_name, avg(salary) as avg_salaryfrom instructorgroup by dept_name;
Aturan wajib:atribut di klausa select yang berada di luar fungsi agregat harus muncul di daftar group by. Query berikut salah karena ID tidak diagregasi dan tidak ada di group by:
/* erroneous query */select dept_name, ID, avg(salary)from instructorgroup by dept_name;
Having Clause
having menyaring grup (bukan baris) berdasarkan predikat yang boleh memuat agregat:
select dept_name, avg(salary) as avg_salaryfrom instructorgroup by dept_namehaving avg(salary) > 42000;
Perbedaan kunci: predikat having diterapkan setelah pembentukan grup, sedangkan predikat where diterapkan sebelum grup dibentuk (pada baris individual).
Summary
union/intersect/except menggabungkan hasil dua subquery dan menghapus duplikat secara default (... all untuk mempertahankan). null = unknown/tidak ada: aritmetika dengan null → null; perbandingan dengan null → unknown (kecuali is null/is not null). Logika tiga-nilai: true and unknown = unknown, false and unknown = false, true or unknown = true; di where, unknown diperlakukan false sehingga baris dibuang. Fungsi agregat avg, min, max, sum, count mengembalikan satu nilai atas multiset kolom; count(*) menghitung baris, count(A)/sum/avg mengabaikan null; count(distinct ...) menghapus duplikat dulu. group by membuat grup — atribut non-agregat di select wajib ada di group by. having menyaring grup dengan predikat agregat setelah grup terbentuk, berbeda dari where yang menyaring baris sebelum grup.
Additional Information
NOT IN dengan subquery ber-NULL — jebakan klasik
Jika subquery pada x NOT IN (subquery) mengembalikan satu saja NULL, seluruh predikat menjadi unknown untuk semuax, sehingga hasilnya kosong — bukan error, tetapi diam-diam salah. Gunakan NOT EXISTS (lihat Nested Subqueries dan With Clause) atau tambahkan WHERE kolom IS NOT NULL di subquery.
Window functions: agregasi tanpa kolaps baris
group by mengurangi jumlah baris. Untuk menghitung agregat sambil mempertahankan setiap baris (mis. gaji dosen vs rata-rata departemennya di baris yang sama), pakai window function: avg(salary) over (partition by dept_name). Juga row_number(), rank(), sum(...) over (order by ...) untuk running total. Masuk standar sejak SQL:2003.
FILTER dan agregasi bersyarat
SQL standar: count(*) filter (where grade = 'A') menghitung hanya baris yang memenuhi syarat, beberapa di satu query. Alternatif portabel: sum(case when grade = 'A' then 1 else 0 end).
Proyek Eksplorasi Mandiri
Buat tabel instructor dengan beberapa salary bernilai NULL. Bandingkan count(*), count(salary), sum(salary), avg(salary), dan sum(salary)/count(*). Jelaskan setiap selisih.
Tulis query “departemen dengan gaji rata-rata > 42000 dan jumlah dosen ≥ 3” memakai group by + having dengan dua kondisi. Lalu tulis ulang tanpa having memakai subquery di from.