PL/SQL Programlama Temelleri
PL/SQL blok yapısı, değişkenler, denetim akışı, koleksiyonlar, kayıtlar, cursor, exception, procedure, function ve package temellerini derleyen ders notları.
PL/SQL bölümü başlangıçta veri tabanı ders notlarının devamıydı. Yordamsal programlama ayrıntıları SQL'in ilişkisel sorgu modelinden farklı bir düşünme biçimi gerektirdiği için burada ayrı bir yazı olarak tuttum. Blok yapısı, scope, cursor, exception ve altprogram konularındaki özgün sıralamayı korudum.
Ünite 1: PL/SQL'e Giriş
PL/SQL ile veri tabanı programlama
PL/SQL, Oracle'ın SQL'e eklediği yordamsal programlama dilidir.
SQL bildirimseldir. PL/SQL ise SQL deyimlerini:
- değişkenler,
- koşullar,
- döngüler,
- hata yönetimi,
- yordamlar,
- fonksiyonlar,
- paketler
ile birleştirir.
PL/SQL'in temel kullanım alanı veri tabanına yakın iş mantığının tanımlanmasıdır.
Blok türleri
PL/SQL'in temel çalışma birimi bloktur.
Bloklar:
- anonim blok,
- saklı yordam,
- saklı fonksiyon,
- paket,
- tetikleyici
gibi yapılarda kullanılabilir.
Dersin ana odağı anonim bloklar, yordamlar, fonksiyonlar ve paketlerdir.
PL/SQL program yapısı
Temel blok:
DECLARE
-- bildirimler
BEGIN
-- çalıştırılabilir deyimler
EXCEPTION
-- hata işleyicileri
END;
/DECLARE ve EXCEPTION bölümleri duruma göre kullanılmayabilir. BEGIN ve END çalıştırılabilir bölümün temelidir.
Blokların çalıştırılması
PL/SQL blokları Oracle istemci araçlarından çalıştırılabilir.
Ders notlarında SQLPlus temel arayüz olarak ele alınır. Günümüzde SQLPlus halen kullanılabilir; bunun yanında SQLcl, SQL Developer ve farklı istemci araçları da aynı veri tabanı motoruyla çalışabilir.
Önemli olan istemci aracı değil, SQL ve PL/SQL kodunun sunucuda geçerli sözdizimi ve çalışma modelidir.
SQL ve PL/SQL dosyaları
SQL ve PL/SQL komutları dosyalarda saklanıp tekrar çalıştırılabilir.
Bu yaklaşım:
- tekrarlanabilirlik,
- sürüm kontrolü,
- gözden geçirme,
- dağıtım otomasyonu
açısından etkileşimli komut girişinden daha güvenlidir.
Değişkenler ve sabitler
PL/SQL değişkenleri bildirim bölümünde tanımlanır.
DECLARE
v_ad VARCHAR2(100);
v_sayac NUMBER := 0;
BEGIN
NULL;
END;
/Sabit:
c_kdv CONSTANT NUMBER := 0.20;SQL deyimlerinin PL/SQL içinde kullanımı
PL/SQL içinde SQL doğrudan çalıştırılabilir.
Tek satır beklenen sorguda:
SELECT AD, UCRET
INTO v_ad, v_ucret
FROM PERSONEL
WHERE PERSONEL_NO = 100;Kardinalite önemlidir. Sorgu sıfır veya birden fazla satır döndürürse istisna oluşabilir.
DML kullanımı
UPDATE PERSONEL
SET UCRET = UCRET * 1.10
WHERE BOLUM_NO = 20;PL/SQL bloğu içindeki DML mevcut transaction bağlamında çalışır.
Transaction deyimleri
Gerektiğinde:
COMMIT;
ROLLBACK;kullanılabilir.
Ancak yeniden kullanılabilir yordamların kendi başına COMMIT yapıp yapmaması mimari bir karardır. Transaction sınırı çoğu uygulamada üst katmanın sorumluluğunda tutulur.
Bağlı değişkenler
Bind variable, SQL metni ile değerleri ayırır.
Kavramsal olarak:
SQL yapısı + parametre değerlerişeklinde düşünülmelidir.
Bağlı değişkenler:
- SQL enjeksiyonu riskini azaltmada,
- sorgu ayrıştırma maliyetini düşürmede,
- plan paylaşımında
önemli olabilir.
Bildirimler bölümü
DECLARE bölümünde:
- değişken,
- sabit,
- tür,
- cursor,
- yerel yordam,
- exception
tanımlanabilir.
Varsayılan değerler
v_sayac NUMBER := 0;veya uygun bağlamda DEFAULT kullanılabilir.
NULL denetimi
PL/SQL'de de SQL'in üç değerli mantığına dikkat edilmelidir.
IF v_deger IS NULL THEN
...
END IF;%TYPE
%TYPE, değişken tipini tablo sütunundan türetir.
v_ucret PERSONEL.UCRET%TYPE;Sütun tipi değiştiğinde kodun veri tipi tanımıyla uyumunu korumayı kolaylaştırır.
%ROWTYPE
Bir tablonun veya cursor sonucunun tüm satır yapısını kayıt tipi olarak kullanır.
v_personel PERSONEL%ROWTYPE;Alanlara:
v_personel.AD
v_personel.UCRETbiçiminde erişilebilir.
Veri türleri
PL/SQL:
- sayısal,
- karakter,
- tarih-zaman,
- Boolean,
- record,
- collection
gibi türler sağlar.
SQL veri tipleriyle PL/SQL veri tipleri büyük ölçüde bütünleşmiştir ancak her tür SQL sütun tipi olarak kullanılamaz.
İfadeler ve işleçler
PL/SQL:
- aritmetik,
- karşılaştırma,
- mantıksal
işleçleri destekler.
Koşullarda NULL semantiği dikkate alınmalıdır.
Açıklama satırları
Tek satır:
-- açıklamaÇok satır:
/*
açıklama
*/Üretim kodunda yorumlar kodun kendisinden çıkarılamayan amacı veya özel gerekçeyi açıklamalıdır.
Ünite 2: Program Denetimi
IF deyimi
IF v_ucret > 50000 THEN
...
END IF;Alternatif:
IF kosul THEN
...
ELSIF baska_kosul THEN
...
ELSE
...
END IF;Koşul gerçekleşmiyorsa
ELSE, diğer koşulların hiçbirinin gerçekleşmediği yolu tanımlar.
İç içe IF
Bir IF bloğu başka bir IF bloğu içerebilir.
Derin iç içe yapı okunabilirliği azaltır. Mantıksal koşullar mümkün olduğunca sade tutulmalıdır.
Temel LOOP
LOOP
...
END LOOP;Çıkış koşulu yoksa sonsuz döngü oluşur.
Koşulsuz çıkış
EXIT;döngüyü sonlandırır.
Koşullu çıkış
EXIT WHEN v_sayac >= 10;WHILE döngüsü
WHILE v_sayac < 10 LOOP
v_sayac := v_sayac + 1;
END LOOP;Koşul her iterasyon öncesinde değerlendirilir.
FOR döngüsü
FOR i IN 1..10 LOOP
...
END LOOP;Belirli aralıkta yineleme için uygundur.
Döngü etiketleri
İç içe döngülerde belirli döngüyü isimlendirmek ve gerektiğinde açıkça hedeflemek için etiketler kullanılabilir.
GOTO
PL/SQL GOTO deyimini destekler.
Ancak modern yapılandırılmış programlama yaklaşımında IF, CASE, döngüler ve altprogramlar çoğu durumda daha okunabilir akış sağlar. GOTO yalnız zorunlu ve açık gerekçesi olan durumlarda düşünülmelidir.
Ünite 3: PL/SQL Koleksiyonları ve Kayıtları
PL/SQL tabloları
Eski Oracle terminolojisindeki PL/SQL table kavramı güncel terminolojide ağırlıklı olarak associative array başlığı altında değerlendirilir.
Bir koleksiyon çok sayıda aynı tür değeri tek değişken altında tutar.
Kavramsal yapı:
anahtar -> değerKoleksiyon tanımlama
Örnek:
DECLARE
TYPE t_adlar IS TABLE OF VARCHAR2(100)
INDEX BY PLS_INTEGER;
v_adlar t_adlar;
BEGIN
v_adlar(1) := 'Ali';
v_adlar(2) := 'Ayse';
END;
/Koleksiyonların kullanımı
Elemanlar indeks üzerinden okunur ve değiştirilir.
Koleksiyonlar PL/SQL tarafında geçici veri kümelerini yönetmek için kullanışlıdır.
Koleksiyon öznitelikleri
Yaygın collection method'ları arasında:
COUNT,FIRST,LAST,DELETE,EXISTS,NEXT,PRIOR
bulunur.
Eleman sayısı
v_adlar.COUNTmevcut eleman sayısını verir.
İlk ve son eleman
v_adlar.FIRST
v_adlar.LASTmevcut indeks sınırlarını verir.
Seyrek koleksiyonlarda 1..COUNT varsayımı her zaman doğru değildir.
Eleman silme
v_adlar.DELETE(2);belirli elemanı kaldırabilir.
Kullanıcı tanımlı kayıtlar
PL/SQL record, farklı türde alanları tek mantıksal nesne altında toplar.
TYPE t_personel IS RECORD (
personel_no NUMBER,
ad VARCHAR2(100),
ucret NUMBER
);Kayıt değişkeni
v_personel t_personel;Alan erişimi:
v_personel.ad%ROWTYPE
Tablo satırını manuel olarak tekrar tanımlamak yerine:
v_personel PERSONEL%ROWTYPE;kullanılabilir.
Bu yaklaşım veri tabanı şemasıyla tip uyumunu artırır.
Ünite 4: İmleçler
İmleç kavramı
Cursor, SQL deyiminin sonuç kümesi üzerinde satır satır işlem yapmaya yarayan PL/SQL mekanizmasıdır.
SQL mümkün olduğunca küme tabanlı kullanılmalıdır. Cursor, satır bazlı iş mantığı gerçekten gerektiğinde kullanılmalıdır.
Örtük imleç
Oracle, DML ve tek satırlı SQL işlemleri için örtük cursor yönetimini otomatik yapar.
Örtük cursor ile ilgili durum bilgileri:
SQL%FOUND
SQL%NOTFOUND
SQL%ROWCOUNT
SQL%ISOPENgibi özniteliklerle okunabilir.
Belirtilmiş imleç
Birden fazla satır üzerinde kontrollü dolaşmak için explicit cursor tanımlanabilir.
CURSOR c_personel IS
SELECT PERSONEL_NO, AD, UCRET
FROM PERSONEL
WHERE BOLUM_NO = 20;Cursor çalışma sırası
Klasik explicit cursor yaşam döngüsü:
- declare,
- open,
- fetch,
- close.
Cursor açma
OPEN c_personel;Sorgu yürütme bağlamını hazırlar.
Veri alma
FETCH c_personel
INTO v_personel_no, v_ad, v_ucret;Her FETCH bir sonraki satırı alır.
Cursor kapatma
CLOSE c_personel;Kaynakları serbest bırakır.
Cursor öznitelikleri
Explicit cursor için:
c_personel%FOUND
c_personel%NOTFOUND
c_personel%ROWCOUNT
c_personel%ISOPENkullanılabilir.
Cursor tabanlı kayıtlar
Cursor satır yapısı %ROWTYPE ile alınabilir.
v_kayit c_personel%ROWTYPE;Cursor FOR döngüsü
PL/SQL cursor açma, fetch ve kapatma işlemlerini otomatik yönetebilir.
FOR r IN (
SELECT PERSONEL_NO, AD
FROM PERSONEL
WHERE BOLUM_NO = 20
) LOOP
...
END LOOP;Basit cursor dolaşımlarında açık OPEN/FETCH/CLOSE kullanımından daha güvenlidir.
Parametreli cursor
CURSOR c_personel(p_bolum_no NUMBER) IS
SELECT PERSONEL_NO, AD
FROM PERSONEL
WHERE BOLUM_NO = p_bolum_no;Aynı sorgu farklı parametrelerle tekrar kullanılabilir.
Ünite 5: Kural Dışı Durumların Denetlenmesi
Exception yönetimi
PL/SQL çalışma zamanı hatalarını exception mekanizmasıyla yönetir.
Bir hata oluştuğunda normal akış durur ve uygun EXCEPTION işleyicisine geçilir.
BEGIN
...
EXCEPTION
WHEN ... THEN
...
END;
/Hata yönetimi güvenilir veri tabanı programlamasının temelidir.
Önceden tanımlı hatalar
Oracle bazı hata durumlarını isimlendirilmiş exception olarak sunar.
Örneğin:
NO_DATA_FOUND,TOO_MANY_ROWS,ZERO_DIVIDE,DUP_VAL_ON_INDEX.
EXCEPTION
WHEN NO_DATA_FOUND THEN
...Önceden tanımlı olmayan sunucu hataları
Belirli Oracle hata kodları kullanıcı tarafından isimlendirilmiş exception ile ilişkilendirilebilir.
Bu amaçla PRAGMA EXCEPTION_INIT kullanılabilir.
Hata kodları
PL/SQL hata bağlamında:
SQLCODE
SQLERRMile hata kodu ve hata metni elde edilebilir.
Bu bilgiler loglama ve hata dönüşümünde kullanılabilir.
Kullanıcı tanımlı exception
DECLARE
e_gecersiz_ucret EXCEPTION;
BEGIN
IF v_ucret < 0 THEN
RAISE e_gecersiz_ucret;
END IF;
EXCEPTION
WHEN e_gecersiz_ucret THEN
...
END;
/İşletme kuralları anlamlı exception'lara dönüştürülebilir.
Hata yönetiminde transaction
Exception yakalanması transaction'ın otomatik olarak istenen şekilde sonuçlandırıldığı anlamına gelmez.
Hata durumunda:
- hangi değişikliklerin geri alınacağı,
- transaction'ın kim tarafından sonlandırılacağı,
- hatanın üst katmana aktarılıp aktarılmayacağı
tasarımın parçasıdır.
Ünite 6: Altprogramlar
Altprogram kavramı
PL/SQL'de yeniden kullanılabilir isimlendirilmiş kod bloklarına altprogram denir.
İki temel tür:
- procedure,
- function.
Altprogramlar:
- tekrar eden kodu azaltır,
- iş mantığını merkezileştirir,
- yetkilendirme sınırı oluşturabilir,
- uygulama ile veri tabanı arasında kararlı arayüz sağlayabilir.
Ortak yapı
Bir altprogram:
- ad,
- parametreler,
- bildirimler,
- çalıştırılabilir bölüm,
- exception bölümü
içerebilir.
Yordamlar
Procedure bir işi yerine getirir.
CREATE OR REPLACE PROCEDURE UCRET_GUNCELLE (
p_personel_no IN NUMBER,
p_yeni_ucret IN NUMBER
) AS
BEGIN
UPDATE PERSONEL
SET UCRET = p_yeni_ucret
WHERE PERSONEL_NO = p_personel_no;
END;
/Anonim blok içindeki yordamlar
Bir procedure yalnız bulunduğu blok içinde kullanılmak üzere yerel tanımlanabilir.
Bu yöntem yardımcı işlemleri bölmek için kullanılabilir.
Saklı yordamlar
Şema düzeyinde oluşturulan procedure veri tabanında derlenmiş nesne olarak saklanır.
Birden fazla uygulama aynı yordamı çağırabilir.
Yordamların çalıştırılması
PL/SQL içinden:
BEGIN
UCRET_GUNCELLE(100, 75000);
END;
/çağrılabilir.
İstemci aracı ve sürücüye göre callable statement mekanizmaları da kullanılabilir.
IN, OUT ve IN OUT parametreleri
IN yalnız giriş değeridir.
OUT yordamın dışarı değer vermesini sağlar.
IN OUT hem giriş hem çıkış amacıyla kullanılabilir.
API tasarımında parametre yönü açık tutulmalıdır.
Fonksiyonlar
Function bir değer döndürür.
CREATE OR REPLACE FUNCTION YILLIK_UCRET (
p_aylik_ucret IN NUMBER
) RETURN NUMBER AS
BEGIN
RETURN p_aylik_ucret * 12;
END;
/Saklı fonksiyonlar
Şema düzeyindeki fonksiyonlar veri tabanı nesnesidir.
Uygun koşullarda SQL ifadeleri içinde de kullanılabilir.
Fonksiyonun yan etkileri ve SQL'den çağrılma kuralları Oracle semantiğine göre değerlendirilmelidir.
Paketler
Package, ilişkili PL/SQL öğelerini tek şema nesnesi altında gruplar.
Bir paket:
- tipler,
- sabitler,
- değişkenler,
- cursor'lar,
- exception'lar,
- procedure'ler,
- function'lar
içerebilir.
Paket belirtimi
Package specification dışarıdan görülebilen arayüzdür.
CREATE OR REPLACE PACKAGE PERSONEL_API AS
PROCEDURE UCRET_GUNCELLE(
p_personel_no IN NUMBER,
p_yeni_ucret IN NUMBER
);
FUNCTION YILLIK_UCRET(
p_aylik_ucret IN NUMBER
) RETURN NUMBER;
END PERSONEL_API;
/Paket gövdesi
Package body, arayüzde belirtilen altprogramların gerçekleştirimini içerir.
CREATE OR REPLACE PACKAGE BODY PERSONEL_API AS
PROCEDURE UCRET_GUNCELLE(
p_personel_no IN NUMBER,
p_yeni_ucret IN NUMBER
) AS
BEGIN
UPDATE PERSONEL
SET UCRET = p_yeni_ucret
WHERE PERSONEL_NO = p_personel_no;
END;
FUNCTION YILLIK_UCRET(
p_aylik_ucret IN NUMBER
) RETURN NUMBER AS
BEGIN
RETURN p_aylik_ucret * 12;
END;
END PERSONEL_API;
/Specification ile body ayrımı, arayüz ile gerçekleştirim ayrımını sağlar.
Paketlerin kullanımı
Paket üyesi:
PERSONEL_API.UCRET_GUNCELLE(...)biçiminde çağrılabilir.
Paketler özellikle ortak veri tabanı işlevlerini tek ad alanında toplamak için uygundur.
Paketlerin tasarım değeri
İyi tasarlanmış paket:
- iç gerçekleştirim ayrıntılarını gizler,
- uygulamaya dar bir API sunar,
- tekrar kullanım sağlar,
- erişim yetkisinin paket düzeyinde verilmesine olanak tanır,
- ilgili fonksiyonları mantıksal olarak bir araya getirir.
Veri tabanı programlama katmanı büyüdükçe bağımsız yordamlar yerine tutarlı paket sınırları oluşturmak bakım maliyetini azaltabilir.