İçeriğe geç
academia.sh

Ders 17 / 18

Görünümler

Adlandırılmış sorgu olarak görünüm tanımı, karmaşıklığı gizleme ve erişimi daraltma işlevleri, güncellenebilirlik koşulları ve görünüm üzerinden yazmanın motora göre değişen davranışı.

İçindekiler

Buraya kadarki deyimlerin hepsi tabloların üzerinde doğrudan çalıştı. Bu dersin konusu araya giren bir katman: sorgunun kendisine ad vermek ve o adı tablo gibi kullanmak.

Bir kütüphane veritabanında aynı sorgu tekrar tekrar yazılır — açık ödünçler, askıdaki üyeler, şube başına kitap sayısı. Sorgu her yazıldığında yeniden düşünülür, her kopyasında ayrı hata yapılabilir ve şema değiştiğinde her kopya ayrı ayrı güncellenmek zorunda kalır. Görünüm (view), bu tekrarı ortadan kaldıran yapıdır.

Görünüm Adlandırılmış Bir Sorgudur

CREATE VIEW deyimi bir sorguya ad verir. Ad kullanıldığında motor, saklanan sorguyu çalıştırır. Görünüm veri tutmaz; bu yüzden sanal tablo olarak da anılır.

sqlite3 :memory: <<'SQL'
.headers on
.mode column
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL,
                  durum TEXT NOT NULL DEFAULT 'etkin');
INSERT INTO uye VALUES (1,'Ayşe','Demir','etkin'),(2,'Mehmet','Kaya','askida'),
                       (3,'Zeynep','Arslan','etkin');

CREATE VIEW etkin_uye AS
  SELECT uye_id, ad, soyad FROM uye WHERE durum = 'etkin';

SELECT * FROM etkin_uye;

UPDATE uye SET durum = 'etkin' WHERE uye_id = 2;
SELECT * FROM etkin_uye;
SQL
uye_id  ad      soyad 
------  ------  ------
1       Ayşe    Demir 
3       Zeynep  Arslan
uye_id  ad      soyad 
------  ------  ------
1       Ayşe    Demir 
2       Mehmet  Kaya  
3       Zeynep  Arslan

Görünümün tanımı arada hiç değişmedi; yalnızca temel tablodaki bir satırın durumu değişti ve görünüm o değişikliği hemen yansıttı. Bu, görünüm ile kopya tablo arasındaki temel farktır: kopya bir andaki durumu dondurur, görünüm sorgunun kendisini saklar.

Görünüm sorgulanırken tablo gibi davranır. WHERE, ORDER BY, birleştirme, hatta başka bir görünüm içinde kullanım — hepsi geçerlidir. Sorgu yazan için görünüm ile tablo arasında bir fark yoktur.

Görünümün İki İşi

Görünümler iki ayrı gereksinimi karşılar. Birincisi karmaşıklığı gizlemektir: birden çok tabloyu birleştiren, gruplayan ve toplama işlevleri kullanan bir sorgu bir kez yazılır, sonra tek bir adla anılır.

sqlite3 :memory: <<'SQL'
.headers on
.mode column
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL);
CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL,
                    uye_id INTEGER NOT NULL, alis_tarihi TEXT NOT NULL, iade_tarihi TEXT);
INSERT INTO uye VALUES (1,'Ayşe','Demir'),(2,'Mehmet','Kaya'),(3,'Zeynep','Arslan');
INSERT INTO odunc VALUES
  (1,1,1,'2025-01-10','2025-01-24'),
  (2,2,1,'2025-02-02','2025-02-20'),
  (3,1,2,'2025-02-11',NULL),
  (9,7,1,'2025-05-14',NULL);

CREATE VIEW uye_ozeti AS
  SELECT u.uye_id, u.ad, u.soyad,
         count(o.odunc_id) AS toplam_odunc,
         sum(CASE WHEN o.odunc_id IS NOT NULL AND o.iade_tarihi IS NULL
                  THEN 1 ELSE 0 END) AS acik_odunc
  FROM uye AS u
  LEFT JOIN odunc AS o ON o.uye_id = u.uye_id
  GROUP BY u.uye_id, u.ad, u.soyad;

SELECT * FROM uye_ozeti ORDER BY uye_id;
SELECT ad, soyad FROM uye_ozeti WHERE acik_odunc > 0 ORDER BY uye_id;
SQL
uye_id  ad      soyad   toplam_odunc  acik_odunc
------  ------  ------  ------------  ----------
1       Ayşe    Demir   3             1         
2       Mehmet  Kaya    1             1         
3       Zeynep  Arslan  0             0         
ad      soyad
------  -----
Ayşe    Demir
Mehmet  Kaya 

İkinci sorgu, bir dış birleştirme ve gruplama yazmak yerine tek bir koşul yazdı. Görünümün üzerine yazılan WHERE koşulu, saklanan sorgunun sonucuna uygulanır.

Toplama koşulundaki o.odunc_id IS NOT NULL parçası dış birleştirmenin bir sonucudur: hiç ödüncü olmayan üye için birleştirme boş değerlerle bir satır üretir ve o satır, koşul yalnızca iade tarihinin boşluğuna baksaydı açık ödünç sayılırdı. Görünüm, bu inceliği bir kez doğru yazıp saklamanın da yoludur.

Görünümün ikinci işi erişimi daraltmaktır. etkin_uye görünümünü sorgulayan biri, üye tablosundaki durum sütununu hiç görmez. Sütun ve satır düzeyinde ne gösterileceği görünümün tanımında belirlenir; okuyucuya temel tablo yerine görünüm verilir. Bu, sonraki dersin konusu olan yetkilendirmenin en çok kullanılan aracıdır.

Görünüme Yazmak

Görünüm tablo gibi sorgulanabiliyorsa, tablo gibi yazılabilir mi. Bu sorunun yanıtı hem görünümün tanımına hem de motora bağlıdır.

sqlite3 :memory: <<'SQL'
.headers on
.mode column
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL,
                  durum TEXT NOT NULL DEFAULT 'etkin');
INSERT INTO uye VALUES (1,'Ayşe','Demir','etkin'),(2,'Mehmet','Kaya','askida');

CREATE VIEW etkin_uye AS SELECT uye_id, ad, soyad FROM uye WHERE durum = 'etkin';

INSERT INTO etkin_uye (uye_id, ad, soyad) VALUES (3,'Zeynep','Arslan');
UPDATE etkin_uye SET soyad = 'Demir Kaya' WHERE uye_id = 1;
DELETE FROM etkin_uye WHERE uye_id = 1;

SELECT * FROM etkin_uye;
SQL
Parse error near line 9: cannot modify etkin_uye because it is a view
Parse error near line 10: cannot modify etkin_uye because it is a view
Parse error near line 11: cannot modify etkin_uye because it is a view
uye_id  ad    soyad
------  ----  -----
1       Ayşe  Demir

Kullanılan motorda görünümler salt okunurdur; üç yazma denemesi de aynı gerekçeyle reddedildi. Bu, motora göre değişen bir karardır — pek çok motor belirli koşulları sağlayan görünümlere doğrudan yazmaya izin verir.

Standart SQL bu koşulları güncellenebilir görünüm başlığı altında tanımlar. Ortak çekirdeği şudur: görünümün her satırı, temel tablodaki tek bir satıra geri izlenebilmelidir. Bunu bozan yazımlar, görünümü salt okunur yapar:

  • Birden çok tablonun birleştirilmesi — bir satır iki tablodan geldiğinde, güncelleme hangisine yazılacağı belirsizdir.
  • Gruplama ve toplama işlevleri — sonuçtaki bir satır birden çok temel satırı özetler.
  • Tekrarların atılması ve küme işlemleri — satırlar arasındaki karşılık kaybolur.
  • Sonuçta ifadeyle üretilen sütunlar — hesaplanmış bir sütuna yazılan değerin girdilere nasıl dağıtılacağı tanımsızdır.

Kalan durum — tek tablodan seçilen, gruplanmamış ve tekrarları atılmamış bir görünüm — kural olarak güncellenebilirdir. Yukarıdaki etkin_uye bu tanıma uyar ve buna karşın reddedildi: koşulun sağlanması, motorun desteklediği anlamına gelmez.

Yazılabilir Görünüm Kurmak

Doğrudan yazmayı desteklemeyen motorlarda, yazmanın ne anlama geldiği açıkça tanımlanır. Görünüm üzerine kurulan bir tetikleyici, deyimin yerine geçer ve temel tabloya yazar.

sqlite3 :memory: <<'SQL'
.headers on
.mode column
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL,
                  durum TEXT NOT NULL DEFAULT 'etkin');
INSERT INTO uye VALUES (1,'Ayşe','Demir','etkin'),(2,'Mehmet','Kaya','askida');

CREATE VIEW etkin_uye AS SELECT uye_id, ad, soyad FROM uye WHERE durum = 'etkin';

CREATE TRIGGER etkin_uye_ekle INSTEAD OF INSERT ON etkin_uye
BEGIN
  INSERT INTO uye (uye_id, ad, soyad, durum)
  VALUES (NEW.uye_id, NEW.ad, NEW.soyad, 'etkin');
END;

INSERT INTO etkin_uye (uye_id, ad, soyad) VALUES (3,'Zeynep','Arslan');
SELECT * FROM uye;
SQL
uye_id  ad      soyad   durum 
------  ------  ------  ------
1       Ayşe    Demir   etkin 
2       Mehmet  Kaya    askida
3       Zeynep  Arslan  etkin 

INSTEAD OF yazımı, adının söylediğini yapar: ekleme deyimi görünüme uygulanmaz, onun yerine gövdedeki deyimler çalışır. NEW, eklenmeye çalışılan satırı adlandırır. Görünümde olmayan durum sütununu tetikleyici doldurdu — görünüme yazmanın anlamı burada tanımlanmış oldu.

Tetikleyicilerin ayrıntısı, örtük yan etkilerinin yarattığı sorunlar dahil, İleri SQL kursuna aittir. Bu derste gösterilen, görünümü yazılabilir kılmanın standart olmayan yolunun bu olduğudur.

Görünümden Kaybolan Satır

Yazılabilir bir görünümün kendine özgü bir tuzağı vardır. Görünüm satırları bir koşulla süzüyorsa, o koşulu sağlamayan bir satır görünüm üzerinden eklenebilir — ve eklendikten sonra görünümde görünmez.

sqlite3 :memory: <<'SQL'
.headers on
.mode column
CREATE TABLE kitap (
  kitap_id INTEGER PRIMARY KEY,
  baslik   TEXT NOT NULL,
  yazar    TEXT NOT NULL,
  sube_id  INTEGER NOT NULL
);
INSERT INTO kitap VALUES (1,'Körlük','José Saramago',1);

CREATE VIEW merkez_kitap AS
  SELECT kitap_id, baslik, yazar, sube_id FROM kitap WHERE sube_id = 1;

CREATE TRIGGER merkez_kitap_ekle INSTEAD OF INSERT ON merkez_kitap
BEGIN
  INSERT INTO kitap (kitap_id, baslik, yazar, sube_id)
  VALUES (NEW.kitap_id, NEW.baslik, NEW.yazar, NEW.sube_id);
END;

INSERT INTO merkez_kitap VALUES (5,'Sessiz Ev','Orhan Pamuk',3);

SELECT * FROM merkez_kitap;
SELECT * FROM kitap;
SQL
kitap_id  baslik  yazar          sube_id
--------  ------  -------------  -------
1         Körlük  José Saramago  1      
kitap_id  baslik     yazar          sube_id
--------  ---------  -------------  -------
1         Körlük     José Saramago  1      
5         Sessiz Ev  Orhan Pamuk    3      

Ekleme başarılı oldu, satır temel tabloya yazıldı — ama merkez şubenin kitaplarını gösteren görünümde yok. Görünümü kullanan biri, az önce eklediği satırı bir daha göremez.

Standart SQL bu durum için görünüm tanımına eklenen bir seçenek tanımlar: görünüm üzerinden yazılan satır, görünümün koşulunu sağlamak zorunda tutulur. Bu seçenek de evrensel değildir.

sqlite3 :memory: <<'SQL'
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, durum TEXT NOT NULL);
CREATE VIEW etkin_uye AS SELECT uye_id FROM uye WHERE durum = 'etkin' WITH CHECK OPTION;
SQL
Parse error near line 2: near "WITH": syntax error
  e AS SELECT uye_id FROM uye WHERE durum = 'etkin' WITH CHECK OPTION;
                                      error here ---^

Standartta yazan bir cümle, kullanılan motorda ayrıştırılamadı bile. Bu davranışın motora göre değiştiğini bilmek, taşınabilir şema yazmanın gereğidir: görünüm koşulunun korunması gerekiyorsa ve motor bu seçeneği tanımıyorsa, denetim tetikleyicinin gövdesinde elle yazılır.

Özet

  • Görünüm veri tutmaz, sorguyu saklar; temel tablodaki her değişikliği anında yansıtır ve sorgulanırken tablo gibi davranır.
  • Görünümün iki işi vardır: birleştirme ve gruplama karmaşıklığını tek adın arkasına almak, ve okuyucuya temel tablonun yalnızca bir bölümünü göstermek.
  • Bir görünümün güncellenebilir olması için her satırının tek bir temel satıra geri izlenebilmesi gerekir; birleştirme, gruplama, tekrar atma ve hesaplanmış sütun bunu bozar.
  • Koşulları sağlayan bir görünümün yazılabilir olması motora bağlıdır; desteklenmediği yerde yazmanın anlamı INSTEAD OF tetikleyicisiyle açıkça tanımlanır.
  • Süzen bir görünüme koşulu sağlamayan satır yazılabilir ve o satır görünümde görünmez; standardın bunu engelleyen seçeneği her motorda bulunmaz.

Sonraki Adım

Görünümün ikinci işi — okuyucuya temel tablo yerine daraltılmış bir pencere vermek — yarım kalmış bir düşüncedir: görünüm sunulsa bile, temel tablonun kendisi hâlâ ortadadır. Onu kimin görebileceğini söyleyen ayrı bir mekanizma gerekir. Kursun son dersi nesne düzeyi izinleri ele alır: yetkinin kime, hangi nesne üzerinde, hangi işlem için verildiği; bu yetkinin geri alınması; ve verilen izinlerin işin gerektirdiğinden fazla olup olmadığının sayılması.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat