Fonksiyon (Function) / Saklı Yordam (Stored Procedure)
Koşul İfadeleri, Döngü İfadeleri
İmleç (Cursor)
Tetikleyici (Trigger)
Hazır Fonksiyonlar
Pagila örnek veritabanını kullanmaktadır. (VB Diyagramı: https://dataedo.com/samples/html/Pagila/doc/Pagila_10/modules/Paglia_database_diagram_103/module.html)
Fonksiyon (Function) / Saklı Yordam (Stored Procedure)
Fonksiyonlar / saklı yordamlar, sistem kataloğunda saklanan SQL ifadeleridir. Fonksiyonlar / saklı yordamlar; uygulama yazılımları, tetikleyici ya da başka bir fonksiyon / saklı yordam tarafından çağrılabilirler.
Avantajları
Uygulamanın başarımını iyileştirir.
Fonksiyonlar / saklı yordamlar, bir defa oluşturulduktan sonra derlenerek sistem kataloğunda saklanır. Her çağrıldıklarında SQL motoru tarafından derlenmek zorunda olan SQL ifadelerine göre çok daha hızlıdır.
Uygulama ile veritabanı sunucusu arasındaki trafiği azaltır.
Uzun SQL ifadeleri yerine fonksiyonun / saklı yordamın adını ve parametrelerini göndermek yeterlidir. Ara sonuçların istemci ve sunucu arasında gönderilmesi önlenir.
Yeniden kullanılabilir (reusable).
Tasarım ve uygulama geliştirme sürecini hızlandırır.
Güvenliğin sağlanması açısından çok kullanışlıdır.
Veritabanı yöneticisi, fonksiyonlara / saklı yordamlara hangi uygulamalar tarafından erişileceğini, tabloların güvenlik düzeyleriyle uğraşmadan, kolayca belirleyebilir.
Dezavantajları
Uygulamanın iş mantığı veritabanı sunucusuna kaydırıldığı için uygulama ile veritabanı arasındaki bağımlılık artar ve veritabanından bağımsız kodlama yapmak gitgide imkansızlaşır.
Görünür veritabanı yapısının arkasında, ilişkileri kolayca anlaşılayamayan başka bir yapı oluştururlar.
Fonksiyon / saklı yordam ile program yazmak, değiştirmek (sürüm kontrolü) ve hata bulmak zordur.
Veritabanı Yönetim Sistemi, veri depolama ve listeleme işlerine ek olarak farklı işler yapmak zorunda da kalacağı için bellek kullanımı ve işlem zamanı açısından olumsuz sonuçlara neden olabilir.
Fonksiyonların / saklı yordamların yapacağı işler uygulama yazılımlarına da yaptırılabilir.
Fonksiyon Örneği 1
CREATE OR REPLACE FUNCTION inch2m(sayiInch REAL)
RETURNS REAL
AS
$$ -- Fonksiyon govdesinin (tanımının) başlangıcı
BEGIN
RETURN 2.54 * sayiINCH / 100;
END;
$$ -- Fonksiyon govdesinin (tanımının) sonu
LANGUAGE plpgsql;
Fonksiyon çağrısı
SELECT * FROM inch2m(10);
Koşul İfadeleri
IF miktar > 0 THEN
...
ELSE
...
END IF;
IF miktar < 100 THEN
...
ELSEIF miktar >= 100 AND miktar < 200 THEN
...
ELSEIF miktar >= 200 AND miktar < 300 THEN
...
ELSE
...
END IF;
CASE
WHEN sonuc > 0 THEN
...
WHEN sonuc < 0 THEN
...
ELSE
...
END CASE;
CASE sonuc
WHEN 0 THEN
...
WHEN 1 THEN
...
ELSE
...
END CASE;
CREATE OR REPLACE FUNCTION "fonksiyonTanimlama"(mesaj text, altKarakterSayisi SMALLINT, tekrarSayisi integer)
RETURNS TEXT -- SETOF TEXT, SETOF RECORD diyerek çok sayıda değerin döndürülmesi de mümkündür
AS
$$
DECLARE
sonuc TEXT; -- Değişken tanımlama bloğu
BEGIN
sonuc := '';
IF tekrarSayisi > 0 THEN
FOR i IN 1 .. tekrarSayisi LOOP
sonuc := sonuc || i || '.' || SUBSTRING(mesaj FROM 1 FOR altKarakterSayisi) || E'\r\n';
-- E: string içerisindeki (E)scape karakterleri için...
END LOOP;
END IF;
RETURN sonuc;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE SECURITY DEFINER;
IMMUTABLE: Aynı girişler için aynı çıkışları üretir. Böylece, fonksiyonun gövde kısmı bir kez çalıştırıldıktan sonra diğer çağrılarda çalıştırılmaz. Optimizasyon mümkün olabilir.
Varsayılan VOLATILE: Fonksiyon değeri değişebilir dolayısıyla optimizasyon yapılamaz.
SECURITY DEFINER: Fonksiyon, oluşturan kullanıcının yetkileriyle çalıştırılır.
Varsayılan SECURITY INVOKER: Fonksiyon, çağıran kullanıcının yetkileri ile çalıştırılır.
plperl dili ile örnek bir fonksiyon örneği aşağıda görülmektedir.
CREATE FUNCTION "kucukOlaniDondur" (INT, INT)
RETURNS INTEGER
AS
$$
if ($_[0] > $_[1])
{
return $_[1];
}
return $_[0];
$$
LANGUAGE "plperl";
Fonksiyon çağrısı
SELECT "kucukOlaniDondur"(12,6)
Fonksiyon Örneği 4
Bir SELECT sorgusunun sonuç kümesi içerisinde dolanımın nasıl yapılacağını gösteren fonksiyon örneği aşağıda gösterilmektedir.
CREATE OR REPLACE FUNCTION kayitDolanimi()
RETURNS TEXT
AS
$$
DECLARE
musteriler customer%ROWTYPE; -- customer."CustomerID"%TYPE
sonuc TEXT;
BEGIN
sonuc := '';
FOR musteriler IN SELECT * FROM customer LOOP
sonuc := sonuc || musteriler."customer_id" || E'\t' || musteriler."first_name" || E'\r\n';
END LOOP;
RETURN sonuc;
END;
$$
LANGUAGE 'plpgsql';
Fonksiyon çağrısı
SELECT kayitDolanimi();
Fonksiyon Örneği 5
Tablo döndüren fonksiyon örneği aşağıdadır.
CREATE OR REPLACE FUNCTION personelAra(personelNo INT)
RETURNS TABLE(numara INT, adi VARCHAR(40), soyadi VARCHAR(40))
AS
$$
BEGIN
RETURN QUERY SELECT "staff_id", "first_name", "last_name" FROM staff
WHERE "staff_id" = personelNo;
END;
$$
LANGUAGE "plpgsql";
CREATE OR REPLACE FUNCTION public.odemetoplami(personelno INTEGER)
RETURNS TEXT
LANGUAGE "plpgsql"
AS
$$
DECLARE
personel RECORD;
miktar NUMERIC;
BEGIN
personel := personelAra(personelNo);
miktar := (SELECT SUM(amount) FROM payment WHERE staff_id = personelNo);
RETURN personel."numara" || E'\t' || personel."adi" || E'\t' || miktar;
END
$$;
Fonksiyon çağrısı
SELECT odemeToplami(2);
Fonksiyon Örneği 7
Argüman listesinde çıkış parametresi tanımlanan fonksiyon örneği aşağıdadır.
CREATE OR REPLACE FUNCTION inch2cm(sayiInch REAL, OUT sayiCM REAL)
AS
$$
BEGIN
sayiCM := 2.54 * sayiINCH;
END;
$$
LANGUAGE "plpgsql";
Fonksiyon çağrısı
SELECT * FROM inch2cm(2);
İmleç (Cursor)
İmleç (cursor), sorgu sonucunun toplu olarak oluşturulması yerine parça parça (satır satır) oluşturulmasını sağlar.
LIMIT ve OFFSET yapılarının da benzer bir işi yaptığını hatırlayınız.
Yük dengeleme, uygulama sunucusunun, veritabanı sunucusunun ve istemci belleğinin verimli kullanımı vb. amaçlar için kullanılabilir.
İmleç Örneği
CREATE OR REPLACE FUNCTION filmAra(yapimYili INTEGER, filmAdi TEXT)
RETURNS TEXT
AS
$$
DECLARE
filmAdlari TEXT DEFAULT '';
film RECORD;
filmImleci CURSOR(yapimYili INTEGER) FOR SELECT * FROM film WHERE release_year = yapimYili;
BEGIN
OPEN filmImleci(yapimYili);
LOOP
FETCH filmImleci INTO film;
EXIT WHEN NOT FOUND;
IF film.title LIKE filmAdi || '%' THEN
filmAdlari := filmAdlari || film.title || ':' || film.release_year|| E'\r\n';
END IF;
END LOOP;
CLOSE filmImleci;
RETURN filmAdlari;
END;
$$
LANGUAGE 'plpgsql';
Fonksiyonlarla / saklı yordamlarla birlikte görünür veritabanı yapısının arkasında başka bir yapı oluştururlar.
Ek iş yükü oluştururlar ve dolayısıyla işlem gecikmeleri artabilir.
Tablolarla ilgili her değişiklikte çalıştıkları için ek iş yükü oluştururlar ve bunun sonucu olarak işlem gecikmeleri artabilir.
Tetikleyici Örneği
NorthWind veritabanı kullanmaktadır.
Ürünlerin birim fiyat değişimlerini izlemek için kullanılan bir tetikleyici örneği aşağıdadır.
CREATE TABLE "public"."UrunDegisikligiIzle" (
"kayitNo" serial,
"urunNo" SmallInt NOT NULL,
"eskiBirimFiyat" Real NOT NULL,
"yeniBirimFiyat" Real NOT NULL,
"degisiklikTarihi" TIMESTAMP NOT NULL,
CONSTRAINT "PK" PRIMARY KEY ("kayitNo")
);
CREATE OR REPLACE FUNCTION "urunDegisikligiTR1"()
RETURNS TRIGGER
AS
$$
BEGIN
IF NEW."UnitPrice" <> OLD."UnitPrice" THEN
INSERT INTO "UrunDegisikligiIzle"("urunNo", "eskiBirimFiyat", "yeniBirimFiyat", "degisiklikTarihi")
VALUES(OLD."ProductID", OLD."UnitPrice", NEW."UnitPrice", CURRENT_TIMESTAMP::TIMESTAMP);
END IF;
RETURN NEW;
END;
$$
LANGUAGE "plpgsql";
CREATE TRIGGER "urunBirimFiyatDegistiginde"
BEFORE UPDATE ON "products"
FOR EACH ROW
EXECUTE PROCEDURE "urunDegisikligiTR1"();
UPDATE "products"
SET "UnitPrice" = 100
WHERE "ProductID" = 4
Before İfadesi
Ekleme ve güncelleme işleminde yeni verinin değiştirilebilmesini/denetimini sağlar
CREATE OR REPLACE FUNCTION "kayitEkleTR1"()
RETURNS TRIGGER
AS
$$
BEGIN
NEW."CompanyName" = UPPER(NEW."CompanyName"); -- büyük harfe dönüştürdükten sonra ekle
NEW."ContactName" = LTRIM(NEW."ContactName"); -- Önceki ve sonraki boşlukları temizle
IF NEW."City" IS NULL THEN
RAISE EXCEPTION 'Sehir alanı boş olamaz';
END IF;
RETURN NEW;
END;
$$
LANGUAGE "plpgsql";
CREATE TRIGGER "kayitKontrol"
BEFORE INSERT OR UPDATE ON "customers" -- veriyi eklemeden/değiştirmeden önce üzerinde işlem yap
FOR EACH ROW
EXECUTE PROCEDURE "kayitEkleTR1"();
SELECT TO_CHAR(current_timestamp, 'HH24:MI:SS:MS'); -- HH12, MS Milisecond, US microsecond
SELECT TO_CHAR(current_timestamp, 'DD/MM/YYYY'); -- YYYY year (4 basamak), YY, TZ time zone
Tarih zaman fonksiyonu kullanımı örneği
Pagila veritabanından film kiralama sürelerinin bulunması
SELECT customer_id, to_char(rental_date, 'DD/MM/YYYY' ), return_date,
age(return_date, rental_date)
FROM rental
WHERE return_date IS NOT NULL
ORDER BY 3 DESC