İlişkisel cebir: birleştirmeler, bölme ve gruplama
Theta, doğal ve dış birleştirmeler, bölme (division), atama ve gruplama (γ) ile çok tablolu sorgular yazmak; “for every” ve “for each” sorularının çözüm kalıpları.
Geçen hafta altı temel operatörle her sorguyu yazabileceğini gördün. Ama kalıbını her seferinde yazmak hem uzun hem hataya açık. Bu hafta kısaltmalar geliyor: birleştirmeler (join), dış birleştirmeler (outer join), bölme (division) ve gruplama (aggregation). Sınavda en çok puan getiren iki kalıp burada: çok tablolu birleştirme ve “for every” = bölme.
Altın kurallar:
- Doğal birleştirme aynı adlı bütün sütunları eşitler. Sadece istediğini değil.
- NULL hiçbir değere eşit değildir. İç birleştirmede NULL’lu satır kaybolur; dış birleştirme geri getirir.
- “Every / all” gördüğün an bölme düşün.
- Gruplama sadece var olan değerlerden grup kurar. Hiç geçmeyen değer 0 ile çıkmaz.
Tablolar geçen haftanın örnek veritabanı: student, course, takes, instructor, department, teaches.
Theta birleştirme ve eşit birleştirme
Theta birleştirme (theta join), çarpım ve seçmenin tek işaretle yazılmış hâlidir:
herhangi bir koşul olabilir ( …). Koşul sadece eşitliklerden oluşuyorsa adı eşit birleştirme (equijoin) olur.
Örnek: aynı bölümde, diğerinden daha çok kazanan hoca çiftleri. Tabloyu kendisiyle birleştirdiğimiz için ρ şart:
| i.name | j.name |
|---|---|
| Aksoy | Demir |
| Celik | Sahin |
EE ve BIO’da tek hoca olduğu için çift çıkmaz. yerine yazsaydın her çift iki kez gelirdi: (Aksoy, Demir) ve (Demir, Aksoy).
Doğal birleştirme: ⋈
Doğal birleştirme (natural join) üç şey yapar:
- al,
- aynı adı taşıyan her sütun çifti için eşitlik seç,
- tekrar eden sütunları bir kez bırak.
: ortak sütun sadece inst_id.
| inst_id | name | dept_name | salary | course_id |
|---|---|---|---|---|
| I1 | Aksoy | CS | 95000 | CS101 |
| I1 | Aksoy | CS | 95000 | CS305 |
| I2 | Demir | CS | 80000 | CS201 |
| I3 | Kaya | EE | 85000 | EE210 |
| I4 | Sahin | MATH | 70000 | MA101 |
| I5 | Celik | MATH | 72000 | MA202 |
6 satır, 5 sütun. Yildiz (I6) eşleşmediği için yok. Ortak sütun hiç yoksa doğal birleştirme düz çarpıma dönüşür.
TUZAK · istemediğin ortak sütun. yazınca
student.dept_nameilecourse.dept_nameda eşitlenir. Sonuç 14 kayıt değil 9: sadece öğrencilerin kendi bölümünden aldığı dersler kalır. Ada’nın MA101’i, Cem’in MA101 ve CS101’i, Defne’nin CS305’i, Gizem’in her şeyi kaybolur. Çözüm: birleştirmeden önce ile fazla sütunu at, ya da açık bir theta koşulu yaz.
Doğal birleştirme değişmeli ve birleşmelidir: . Sütun sırası değişebilir, içerik aynı kalır.
Zincir birleştirme
Galata binasındaki bölümlerin derslerini veren hocalar: teaches → course (course_id) → department (dept_name).
Galata’da CS ve EE var. Bu bölümlerin derslerini I1, I2 ve I3 veriyor.
Dış birleştirmeler
İç birleştirme eşi olmayan satırı atar. Bazen o satır tam olarak istediğin şeydir: “ders vermeyen hocalar da listede görünsün”. Dış birleştirme (outer join) eşleşmeyen satırları korur, eksik sütunları NULL ile doldurur.
| İşaret | Ad | Korunan |
|---|---|---|
| ⟕ | left outer join | soldaki eşsiz satırlar |
| ⟖ | right outer join | sağdaki eşsiz satırlar |
| ⟗ | full outer join | iki taraftakiler de |
instructor ⟕ teaches (sütunların bir kısmı):
| inst_id | name | course_id |
|---|---|---|
| I1 | Aksoy | CS101 |
| I1 | Aksoy | CS305 |
| I2 | Demir | CS201 |
| I3 | Kaya | EE210 |
| I4 | Sahin | MA101 |
| I5 | Celik | MA202 |
| I6 | Yildiz | NULL |
teaches ⟖ course ise BI100’ü (inst_id = NULL) getirir. Sağ dış birleştirme, tarafları değiştirilmiş sol dış birleştirmedir: R ⟖ S = S ⟕ R (sütun sırası hariç).
student ⟗ department (dept_name üzerinde):
| stu_id | name | dept_name | building |
|---|---|---|---|
| S1 | Ada | CS | Galata |
| S2 | Bora | CS | Galata |
| S3 | Cem | EE | Galata |
| S4 | Defne | MATH | Rumeli |
| S5 | Ece | CS | Galata |
| S6 | Firat | EE | Galata |
| S7 | Gizem | NULL | NULL |
| NULL | NULL | BIO | Kadikoy |
Gizem solda eşsiz kaldı (NULL bölüm), BIO sağda eşsiz kaldı (öğrencisi yok). 6 + 1 + 1 = 8 satır.
TUZAK · SQL lehçeleri. Standart SQL’de
FULL OUTER JOINvar. SQLite bunu 3.39 sürümünden beri destekliyor; daha eski SQLite ve MySQL desteklemez. O zaman sol dış birleştirmeyi, sağ taraftaki eşsiz satırlarlaUNIONyaparak taklit edersin. Bu sayfadaki sonuç iki yolla da doğrulandı.
Bölme: ÷
Bölme (division) şu soruyu cevaplar: “B’deki her değerle eşleşen A değerleri hangileri?” sonucu, ‘deki her için olan ‘lardır.
Örnek: bütün CS derslerini alan öğrenciler.
Bölen {CS101, CS201, CS305}. Sonuç: S1. Bora CS305’i, Ece CS201 ve CS305’i almadığı için elenir.
Temel operatörlerle türetme
Bölme temel değildir:
Fikir: herkes eksi “en az bir eksiği olanlar”. Adım adım (, = CS dersleri):
1) π_stu_id(T) = {S1, S2, S3, S4, S5, S7} aday öğrenciler
2) π_stu_id(T) × CS = 6 · 3 = 18 satır herkes her CS dersini alsaydı
3) (2) − T = 10 satır eksik kalan (öğrenci, ders) çiftleri
S2-CS305 S3-CS201 S3-CS305 S4-CS101 S4-CS201
S5-CS201 S5-CS305 S7-CS101 S7-CS201 S7-CS305
4) π_stu_id(3) = {S2, S3, S4, S5, S7} eksiği olanlar
5) (1) − (4) = {S1}
Aynı sorguyu SQL’de çift NOT EXISTS ile yazarsın (“almadığı bir CS dersi bulunmayan öğrenci”). 7. haftada göreceksin.
TUZAK · bölünenin sütunları. ‘de sadece ve sütunları olmalı. yazıp
grade’i bırakırsan = (stu_id, grade) olur ve sorgu bambaşka bir şey sorar. Bölmeden önce mutlaka ile daralt.
Atama: ←
Uzun ifadeleri parçalamak için geçici ilişki tanımlarsın:
cs_courses ← π_course_id(σ_{dept_name='CS'}(course))
enrol ← π_stu_id,course_id(takes)
result ← enrol ÷ cs_courses
Atama (assignment) yeni güç eklemez; okunabilirlik kazandırır. Sınavda karmaşık sorularda kullanmak puan kaybettirmez, çoğu zaman hata yapmanı engeller.
Genelleştirilmiş izdüşüm
Genelleştirilmiş izdüşüm (generalized projection), π listesinde aritmetik ifadelere izin verir. MATH hocalarına %10 zam:
Sonuç: Sahin 77000, Celik 79200.
Gruplama ve toplu fonksiyonlar: 𝒢
Toplu fonksiyonlar (aggregate functions) bir değer kümesinden tek değer üretir: count, sum, avg, min, max. Gruplama (grouping) işareti:
Soldaki alt simge gruplama sütunları, sağdaki toplu fonksiyonlar. Bazı kaynaklar harfini kullanır, anlamı aynı.
Bölüm başına ortalama maaş ve hoca sayısı:
| dept_name | avg(salary) | count(inst_id) |
|---|---|---|
| CS | 87500 | 2 |
| EE | 85000 | 1 |
| MATH | 71000 | 2 |
| BIO | 60000 | 1 |
Gruplama sütunu yazmazsan bütün tablo tek grup olur: = (462000, 95000).
Kurallar:
- Toplu fonksiyonlar NULL değerleri atlar. = 6, tabloda 7 satır var.
- Grup sonucu üzerinde koşul (SQL’deki HAVING) için gruplamanın üstüne σ yazarsın. Bunun için toplu sonuca
asile ad ver: → CS, EE. - Girdide hiç geçmeyen bir değer için grup oluşmaz.
Hangi soruya hangi operatör
| Sorudaki ifade | Kalıp |
|---|---|
| “… with their department’s building” | ⋈ (doğal ya da eşit) |
| “including those who have none” | dış birleştirme |
| “pairs of … in the same …” | ρ ile kendi kendine theta birleştirme |
| “took every / all …” | ÷ |
| “never / no …” | fark |
| “for each department, the number of …” | |
| “departments where the average … exceeds” | 𝒢 sonra σ |
Sık yapılan hatalar
| Yanlış düşünce | Doğrusu |
|---|---|
| ⋈ sadece anahtar sütunu eşitler | Aynı adlı bütün sütunları eşitler |
| bütün kayıtları verir | dept_name da eşleşir, 9 satır kalır |
| Dış birleştirme sonuç satır sayısı = sol tablo satır sayısı | Bir satır birden çok eşleşebilir; Aksoy iki kez geçer |
| NULL = NULL eşleşir | Eşleşmez; Gizem hiçbir bölümle eşleşmedi |
| “Every” sorusunu ∩ ile çözmek | Bölen kümenin boyutu değişebilir; ÷ kullan |
| Bölmeden önce π’yi atlamak | Fazla sütun ‘ya karışır, sonuç bozulur |
| Gruplama 0 sayılı grubu da gösterir | Hiç geçmeyen değer çıkmaz (BI100 yok) |
| count(A) satır sayısıdır | NULL’ları atlar; satır için count(*) |
Kendini test et
Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.
How many tuples are in the result of instructor ⟕ teaches (left outer join on inst_id)?
Cevabı göster
İç birleştirme 6 satır verir (Aksoy iki ders verdiği için iki kez geçer). Sol dış birleştirme, eşleşmeyen sol satırları da NULL ile ekler. Ders vermeyen tek hoca I6 (Yildiz): 6 + 1 = 7.
Write a relational algebra expression for the names of instructors who teach CS305. Give the result.
Cevabı göster
ile tek ortak sütun inst_id üzerinden doğal birleşir. Sonra satır koşulu, en son izdüşüm:. CS305'i sadece I1 veriyor: Aksoy.
How many tuples does (natural joins) return on the sample data? Why is it not 14?
Cevabı göster
ortak sütun stu_id ile 14 satır. Ama course ile ortak sütunlar course_id ve dept_name. Doğal birleştirme ikisini de eşitler, yani sadece öğrencinin kendi bölümünün dersleri kalır: Ada 3, Bora 2, Cem 1 (EE210), Defne 2, Ece 1. Toplam 9. Gizem'in bölümü NULL, hiç eşleşmez. Bütün kayıtları istiyorsan course'u önce ile daralt.
Write a relational algebra expression for the IDs of students who took every MATH course. Give the result.
Cevabı göster
“Every / all” kalıbı bölmedir. Bölen: MATH dersleri {MA101, MA202}..
MA101 alanlar: S1, S3, S4. MA202 alanlar: S4, S7. İkisini birden alan sadece S4.
Give the result of . Does BI100 appear?
Cevabı göster
takes satırları course_id'ye göre gruplanır, her grupta satır sayılır. CS101: S1, S2, S3, S5 = 4. CS201: 2. CS305: 2. EE210: 1. MA101: S1, S3, S4 = 3. MA202: 2.
Gruplama sadece girdide var olan değerlerden grup üretir. BI100 takes içinde hiç geçmiyor, 0 ile bile çıkmaz. 0 görmek istersen önce dış birleştirme yapmalısın.
How many students in CS101 have a grade, i.e. what is ?
Cevabı göster
CS101'de 4 kayıt var: S1 (A), S2 (B), S3 (NULL), S5 (F). count(grade) NULL değerleri saymaz: 3. Satır sayısını isteseydin count(stu_id) ya da SQL'de COUNT(*) ile 4 alırdın.
Write a relational algebra expression for the departments that have no instructor teaching any course. Give the result.
Cevabı göster
Ders veren hocaların bölümleri: = {CS, EE, MATH}. Bütün bölümlerden çıkar: BIO. BIO'nun hocası Yildiz var ama ders vermiyor, bu yüzden sonuçta.
How many tuples does student ⟗ department (full outer join on dept_name) have?
Cevabı göster
Eşleşen satırlar: bölümü olan 6 öğrenci (S1..S6), her biri kendi bölümüyle. Eşleşmeyen sol satır: Gizem (dept_name NULL, NULL hiçbir şeye eşit değil). Eşleşmeyen sağ satır: BIO (öğrencisi yok). 6 + 1 + 1 = 8.
Write a relational algebra expression for the IDs of courses taken by all CS students. Give the result.
Cevabı göster
Bu sefer “her öğrenci” bölen tarafta: CS öğrencileri {S1, S2, S5}. Bölünen , sonuç course_id.
CS101'i S1, S2, S5 almış: geçer. CS201'i S5 almamış, CS305'i S2 ve S5 almamış. Sonuç: CS101.
Give the result of .
Cevabı göster
Her kayda dersin kredisi eklenir, sonra öğrenci başına toplanır. S1: 4+4+3+4 = 15. S2: 4+4 = 8. S3: 3+4+4 = 11. S4: 4+3+3 = 10. S5: 4. S7: 3. S6 kayıt yaptırmadığı için grubu yok.course'u ile daralttık. Burada takes ile course arasındaki tek ortak sütun zaten course_id, ama ifadeye student eklendiği an dept_name sorun çıkarır. Daraltmayı alışkanlık edin.
What is ? Compare with the number of tuples in .
Cevabı göster
count(A) sadece NULL olmayan A değerlerini sayar. Gizem'in bölümü NULL, sayılmaz: 6. Tabloda 7 satır var. SQL'de COUNT(dept_name) = 6, COUNT(*) = 7.
Write an expression for the departments whose average instructor salary is greater than 75000. Give the result.
Cevabı göster
Önce grupla ve ortalamaya ad ver: → CS 87500, EE 85000, MATH 71000, BIO 60000.
Sonra grup sonucu üzerinde seçme: , en dışta . Sonuç CS ve EE. Bu, SQL'deki HAVING'in cebirdeki karşılığıdır.
Doğrulama: Bütün sonuç tabloları verify/SEN2104/05.mjs içinde lib.mjs ile (njoin, theta, leftOuter, rightOuter, fullOuter, divide, gamma) hesaplandı; bölme adım adım temel operatörlerle de kuruldu. Her ifadenin SQL karşılığı node:sqlite (SQLite 3.53, FULL OUTER JOIN destekli) üzerinde çalıştırılıp aynı sonuç alındı (56 kontrol, 0 hata).