Bu yazıda verilecek örnek kodlar Sybase Adaptive Server Anywhere ve Interbase6 üzerinde çalıştığı test edilmiş kodlardır. Kodlar içinde kullanılan SQL cümleleri standart SQL cümleleri olması sebebi ile diğer veritabanlarında da kolayca çalışacaktır. Sadece trigger ve stored procedure tanımlamalarındaki kod yapısı farklılıklar göstermektedir. Çalışacağınız veritabanında nasıl trigger ve stored procedure tanımlanabileceğini öğrenerek bu denemeleri yapmak mümkün olabilir. İtiraf edeyim ki yazı biraz uzun olduğu için tekrar baştan aşağı okumadım. Yaptığım hataları uyarmanız sonucu düzeltmekten memnuniyet duyarım.Trigger Nedir
Bir tablo üzerinde belirli bir olaya bağlı olarak tetiklenip çalışan SQL kodlarıdır. Tablo üzerindeki triggerları tetikleyen olaylar insert, update, delete olaylarıdır. Bu olaylara istinaden 3 ana tip triggerdan bahsedilir. Bunlar insert triggerı update triggerı, delete triggerı şeklindedir. Bir tablo üzerinde bu olayların öncesinde ve sonrasında tetiklenecek istenildiği kadar trigger yazılabilir. Fakat genel eğilim ve kullanım her bir olay için tek bir trigger kullanmak şeklindedir.Örneğin stok hareketleri sonucunda stok miktarlarının azalması veya artması işlemlerinin, veya tahakkuk ve tahsilatlar sonucu cari hesapların etkilenmesi işlemlerinin triggerlar aracılığı ile yapılmaları tipik bir trigger kullanım yeridir. Ayrıca referential integrity’yi sağlamak amacı ile de trigger kullanımı çok tercih edilir. İlişkisel bir veritabanında örneğin PERSONEL tablosundaki kişinin bolum bilgisi amaçlı olarak BOLUM_NO tutulması ve bolumun adının da BOLUM tablosundan bulunması yapıldığını düşünürsek. Eğer 1 numaralı bolum herhangi bir personele kullanıldıysa BOLUM tablosundan BOLUM_NO değeri 1 olan kaydın kesinlikle silinememesi gerekmektedir. Bu tür kontrollerin yapılarak veri bütünlüğünün korunmasıdır referential integrity. Bu amaçla yazılan veya bir veritabanı tasarım aracı kullanıldıysa onun otomatik olarak yazdığı trigger kodları sayesinde bu bütünlük korunur. Çünkü BOLUM tablosunun delete trigger’inda gerekli kontrolleri yapacak kod yazılır ve eğer silinmek istenen BOLUM_NO herhangi bir personel için kullanıldıysa bu silme işlemine izin verilmez.Stored Procedure
Stored Procedure ise bir tabloya bağlı olmaksızın veritabanı içinde tanımlanan belirli bir işi yapmaya yönelik kodlardır. Bu kodlar yazıldığı zaman aynı zamanda compile edildikleri için query optimizer tarafından optimize edilmiş en hızlı şekilde çalışmaya hazır kodlardır. Bu kodlar hem triggerlar içinden hem de veritabanı dışındaki her hangi bir ortamdan (Delphi içinden) kolayca çağırılabildikleri için kullanım amaçları geniştir.Örneğin her türlü raporu stored procedure kullanarak yazmak mümkündür ve de tavsiye edilir. Örneğin Delphi tarafında veritabanı üzerinde işler yapan bir fonksiyonunuzu stored procedure haline getirmek işlemlerin çok daha hızlı çalışacak olması sebebi ile tavsiye edilir.Hem trigger hem de stored procedure veritabanı üzerindeki kodlar olmaları sebebi ile veritabanını sunan Server üzerinde çalışırlar. Client&Server mimarinin güçlü enstrümanlarındandırlar. Client Server mimarideki SQL veritabanları tarafından desteklenmektedir. (Oracle, Sybase, MS SQL, Interbase, FireBird vs..) Verilerin bulunduğu Server üzerinde çalışmalarından dolayı veriler client ile Server arasında gidip gelmezler ve de serverdan client tarafına minimum veri çekilmiş olur. Ayrıca yazacağınız stored procedure verilerle çok yoğun uğraşmıyor bile olsa eğer güçlü bir sunucunuz varsa client makinenizin işlemcisinden tasarruf için bile bazı işleri server işlemcisine yüklemek adına stored procedure yazılabilir. Ya da çok kullanıcılı bir sistemde programlar içinde kullanılan tarih ve saat bilgisinin serverdan alınabilmesi için de stored procedure kullanmak basit de olsa bir kullanım şekli olabilir.Bir örnek ile hem trigger hem de stored procedure kullanımının teknik detayına inelim. Söyle bir örneğimiz olsun. Çok basit olarak bir URUN tablosu ve bu tabloda stok miktarı tutuluyor olsun. URUN_GIRIS ve URUN_SATIS seklinde 2 tane de ürünlerin hareketlerini tutacağımız farklı tablolar olsun. Tabloların yapısı şu şekilde olsun.URUN (URUN_NO, URUN_ADI,STOK_MIKTARI)URUN_GIRIS (URUN_NO, GIRIS_ZAMANI, GIRIS_MIKTARI)URUN_SATIS (URUN_NO, SATIS_ZAMANI, SATIS_MIKTARI)URUN_STOK (URUN_NO, STOK_MIKTARI)Tabloları ilişkisel bir şekilde oluşturacak SQL kodu son bölümde ek olarak verilmiştir.Şimdi yapmak istediğimizi açıklayalım. URUN_GIRIS tablosuna kayıtlar girdikçe yani bir üründen belirli miktarlarda girişler yapıldıkça o ürüne ait URUN tablosundaki STOK_MIKTARI alanının değerini giriş miktarı kadar arttırmalıyız. Tabi ki bunun tersi de olabilmeli yani yapılmış bir ürün girişi kaydı silinirse de bu sefer STOK_MIKTARI değeri silinen giriş kadar azaltılarak eski haline getirilmeli. Ve de eğer giriş miktarı diyelim ki 100 adet iken 50 adet olarak değiştirilirse de bu sefer bu duruma göre o ürünün STOK_MIKTARI alanı güncellenebilmeli. Bunu şu şekilde yapacağız. Öncelikle bir stored procedure yazacağız bu stored procedure’e parametre olarak URUN_NO ve GIRIS_MIKTARI’ nı göndereceğiz ve ilgili ürünün STOK_MIKTARI’ nı giriş miktarı kadar arttıracak. Yazdığımız bu stored procedure’ u de URUN_GIRIS tablosunun insert triggerından çağıracağız.Insert triggerından çağıracağımız stored procedure’un adı SPI_URUN_GIRIS olsun. Bu procedur’un kodu şu şekildedir.Kod:Sybase içinCreate procedure dba.SPI_URUN_GIRIS(@URUN_NO integer,@GIRIS_MIKTARI integer)asbegindeclare @DLR_KAYIT_SAYISI integerselect @DLR_KAYIT_SAYISI = count(*) from dba.URUN_STOK where URUN_NO = @URUN_NOif @DLR_KAYIT_SAYISI = 0insert into dba.URUN_STOK(URUN_NO,STOK_MIKTARI) values(@URUN_NO,0)update dba.URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI+@GIRIS_MIKTARI whereURUN_NO = @URUN_NOEnd;Interbase içinCREATE PROCEDURE SPI_URUN_GIRIS ( URUN_NO INTEGER, GIRIS_MIKTARI INTEGER) ASDECLARE VARIABLE DLR_KAYIT_SAYISI integer;beginselect count(*)from URUN_STOK where URUN_NO = :URUN_NOINTO DLR_KAYIT_SAYISI;if (DLR_KAYIT_SAYISI=0) theninsert into URUN_STOK(URUN_NO,STOK_MIKTARI) values(:URUN_NO,0);update URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI+:GIRIS_MIKTARI whereURUN_NO = :URUN_NO;EndDelete triggerından çağıracağımız stored procedure’un adı SPD_URUN_GIRIS olsun. Bu procedur’un kodu şu şekildedir.Kod:Sybase içinCreate procedure dba.SPD_URUN_GIRIS(@URUN_NO integer, @GIRIS_MIKTARI integer)asbeginupdate dba.URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI-@GIRIS_MIKTARI whereURUN_NO = @URUN_NOdelete from dba.URUN_STOK whereURUN_NO = @URUN_NO and STOK_MIKTARI = 0endInterbase içinCREATE PROCEDURE SPD_URUN_GIRIS ( URUN_NO INTEGER, GIRIS_MIKTARI INTEGER) ASbeginupdate URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI-:GIRIS_MIKTARI whereURUN_NO = :URUN_NO;delete from URUN_STOKwhere URUN_NO=:URUN_NO and STOK_MIKTARI=0;endBu stored procedure’lari insert ve delete triggerlarindan çağırılmasını da şöyle yapacağız. URUN_GIRIS tablosunun insert trigger’inin sonuna şu kodu ekleyeceğiz.Kod:Sybase içincall SPI_URUN_GIRIS(newrows.URUN_NO, newrows.GIRIS_MIKTARI);Interbase içinexecute procedure SPI_URUN_GIRIS NEW.URUN_NO, NEW.GIRIS_MIKTARI;URUN_GIRIS tablosunun delete triggerının sonuna da şu kodlar eklenecek. Tabi bizim örneğimizde bu tablo için bir delete triggeri oluşmadığından delete triggerının oluşturulmasını da içerecek kodu verelim.Kod:Sybase içinCreate trigger tD_URUN_GIRIS after delete on DBA.URUN_GIRISreferencing old as oldrowsfor each rowbegincall SPD_URUN_GIRIS(oldrows.URUN_NO,oldrows.GIRIS_MIKTARI)endInterbase içinCREATE TRIGGER TD_URUN_GIRIS FOR URUN_GIRIS AFTER DELETE POSITION 0 ASBEGINexecute procedure SPD_URUN_GIRIS OLD.URUN_NO, OLD.GIRIS_MIKTARI;ENDTriggerlara eklenen bu kodlar sayesinde bir ürün girişi olması durumunda veya bu ürün girişinin silinmesi durumunda URUN tablosundaki STOK_MIKTARI gerekli şekilde düzenlenmiş olacaktır. Bunu görebilmek için önce URUN tablosuna bilgi irişi anlamında şu kodları çalıştırarak tabloyu dolduralım.Kod:insert into URUN(URUN_NO,URUN_ADI) values (1,’Defter’);insert into URUN(URUN_NO,URUN_ADI) values (2,’Kalem’);insert into URUN(URUN_NO,URUN_ADI) values (3,’Silgi’);Bu kodların çalışması sonucunda bütün ürünlerin STOK_MIKTAR larının sıfır olduğu görülebilir. Daha sonra da her üründen belirli miktarlarda giriş için URUN_GIRIS tablosuna kayıt girelim.Kod:insert into URUN_GIRIS(URUN_NO,GIRIS_MIKTARI) values (1,10);insert into URUN_GIRIS(URUN_NO,GIRIS_MIKTARI) values (2,20);insert into URUN_GIRIS(URUN_NO,GIRIS_MIKTARI) values (3,25);Bu kodları çalıştırdıktan sonra da STOK_MIKTARI alanının girişi yapılan miktarlar kadar arttığı görülecektir. Hatta yukarıdaki kodları tekrar çalıştırarak artan STOK_MIKTARI gözlenebilir. Şimdi de örneğin 3 numaralı ürün için yaptığımız girişlerin aslında olmayacağını anlayıp bunları silelim.Kod:Delete from URUN_GIRISI where URUN_NO=3;Bu durumda 3 numaralı ürün için STOK_MIKTARININ tekrar sıfıra düştüğü görülecektir.Şimdi gelelim en çok hoşuma giden noktaya. Aslında iki tane stored procedure yazmak yerine bu procedureler içindeki kodları doğrudan trigger içinde yazabilirdik. Aslında doğru. Fakat iş update triggerına gelince iş biraz değişiyor. Kişi hem URUN_NO alanını update etmiş olabilir hem de GIRIS_MIKTARI alanını, dolayısıyla yapılan update ile ilgili bu en basit örneğimizde bile bir takım kontroller yapmak durumunda kalacağız. Sonuçta çalışan bir kodu yazmak belki çok da zor olmayabilir ama. Projenin daha komplike olduğunu ve de benim bir çok projemde olduğu gibi insert triggerından çağırılan procedure’un onlarca satırdan oluşabildiğini ve farklı farklı bir çok tabloya bilgi güncelleyebildiğini düşünürseniz. O zaman iş update triggerını hatasız yazmaya gelince çok zor olurdu eğer bu kodları procedure içinde değil de doğrudan trigger içinde yazsaydık.Bu durumda yaptığımız ise aynen şudur. Update triggerı içinden update işlemini bir silme ve bir insert işleminin birleşimi gibi düşünüp update edilmeden önceki değerler ya da silinen değerler ile SPD ile başlayan yani delete triggerından çalıştırdığımız procedure’u, onun arkasından da yeni değerler ile yani insert edildiğini varsaydığımız değerler ile de SPI ile başlayan yani insert triggerından çağırılan procedure’u çağırmamız yeterli olacaktır. URUN_GIRIS tablosunun update triggerının sonuna eklenmesi gerekli kod şu şekildedir.Kod:Sybase içincall SPD_URUN_GIRIS(oldrows.URUN_NO,oldrows.GIRIS_MIKTARI);call SPI_URUN_GIRIS(newrows.URUN_NO, newrows.GIRIS_MIKTARI);Interbase içinexecute procedure SPD_URUN_GIRIS OLD.URUN_NO, OLD.GIRIS_MIKTARI;execute procedure SPI_URUN_GIRIS NEW.URUN_NO, NEW.GIRIS_MIKTARI;Şimdi de yeni durumda yapılan bir girişi elle değiştirerek yeni duruma göre STOK_MIKTARI’ nın değiştiğini görebilirsiniz.Yeri gelmişken burada nemli bir noktaya değinelim. Örneğin:Kod:update URUN_GIRISI set GIRIS_MIKTARI=GIRIS_MIKTARI+5;şöyle bir kod çalıştırmanın sonucunu nasıl bekliyoruz? Yaptığımız bütün girişleri 5 adet arttırdığımıza göre her giriş miktarının 5 arttırılması sırasında stored procedurelerimiz çalışacak ve gerekli STOK_MIKTARI artışlarını sağlayacaktır. Yani örneğin 1 numaralı ürün için 7 ve 10 adetlik farklı iki giriş olduysa stokta 17 adet var demektir. Bu girişler 12 ve 15’e değişeceği için stok miktarı da 27’ye değişecektir. Eğer kullandığınız veritabanı row level triggerı destekliyorsa aynen böyle olacaktır. Yani triggerlar her row için ayrı ayrı çalışacaktır. Binlerce kaydınız olsa bile. Ama eğer statement level trigger desteği olan bir veritabanı kullanıyorsanız o zaman insert triggerınız sadece bir defaya mahsus çalışacağı için beklediğimiz etki olmayacaktır. Statement level trigger destekli veritabanı kullanan arkadaşların bu duruma göre daha farklı kodlar yazmaları gerekmektedir. Eğer değişmediyse benim bilgim dahilinde MS SQL statement level trigger destekliyordu. Bunun haricinde Oracle, Sybase, Interbase ve FireBird gibi veritabanları row level trigger desteği vermektedirler.Benzer şekilde URUN_SATIS tablosunun triggerlarından çağırılmak üzere stored procedureleri ve triggerları yazalım.Kod:Sybase içincreate procedure dba.SPI_URUN_SATIS(@URUN_NO integer,@SATIS_MIKTARI integer)asbegindeclare @DLR_KAYIT_SAYISI integerselect @DLR_KAYIT_SAYISI = count(*) from dba.URUN_STOK where URUN_NO = @URUN_NOif @DLR_KAYIT_SAYISI = 0insert into dba.URUN_STOK(URUN_NO,STOK_MIKTARI) values(@URUN_NO,0)update dba.URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI-@SATIS_MIKTARI whereURUN_NO = @URUN_NOendcreate procedure dba.SPD_URUN_SATIS(@URUN_NO integer, @SATIS_MIKTARI integer)asbeginupdate dba.URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI+@SATIS_MIKTARI whereURUN_NO = @URUN_NOdelete from dba.URUN_STOK whereURUN_NO = @URUN_NO and STOK_MIKTARI = 0endInterbase içinCREATE PROCEDURE SPI_URUN_SATIS ( URUN_NO INTEGER, SATIS_MIKTARI INTEGER) ASDECLARE VARIABLE DLR_KAYIT_SAYISI integer;beginselect count(*)from URUN_STOK where URUN_NO = :URUN_NOINTO DLR_KAYIT_SAYISI;if (DLR_KAYIT_SAYISI=0) theninsert into URUN_STOK(URUN_NO,STOK_MIKTARI) values(:URUN_NO,0);update URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI-:SATIS_MIKTARI whereURUN_NO = :URUN_NO;EndCREATE PROCEDURE SPD_URUN_SATIS ( URUN_NO INTEGER, SATIS_MIKTARI INTEGER) ASbeginupdate URUN_STOK setSTOK_MIKTARI = STOK_MIKTARI+:SATIS_MIKTARI whereURUN_NO = :URUN_NO;delete from URUN_STOKwhere URUN_NO=:URUN_NO and STOK_MIKTARI=0;endSybase URUN_SATIS tablosunun insert triggerı sonuna eklenecek kod:Kod:call SPI_URUN_SATIS(newrows.URUN_NO,newrows.SATIS_MIKTARI)Sybase URUN_SATIS tablosunun delete triggerı su şekilde oluşturulacaktır.Kod:create trigger tD_URUN_SATIS after delete on DBA.URUN_SATISreferencing old as oldrowsfor each rowbegincall SPD_URUN_SATIS(oldrows.URUN_NO,oldrows.SATIS_MIKTARI);end;Sybase URUN_SATIS tablosunun update triggerı sonuna eklenecek kod:Kod:call SPD_URUN_SATIS(oldrows.URUN_NO,oldrows.SATIS_MIKTARI);call SPI_URUN_SATIS(newrows.URUN_NO,newrows.SATIS_MIKTARI)Interbase URUN_SATIS tablosunun insert triggerı sonuna eklenecek kod:Kod:execute procedure SPI_URUN_GIRIS NEW.URUN_NO, NEW.GIRIS_MIKTARI;Interbase URUN_SATIS tablosunun delete triggerı su şekilde oluşturulacaktır.Kod:CREATE TRIGGER TD_URUN_SATIS FOR URUN_SATIS AFTER DELETE POSITION 0 ASBEGINexecute procedure SPD_URUN_SATIS OLD.URUN_NO, OLD.SATIS_MIKTARI;ENDInterbase URUN_SATIS tablosunun update triggerı sonuna eklenecek kod:Kod:execute procedure SPD_URUN_GIRIS OLD.URUN_NO, OLD.GIRIS_MIKTARI;execute procedure SPI_URUN_GIRIS NEW.URUN_NO, NEW.GIRIS_MIKTARI;Stored Procedure ile rapor hazırlamaya da bir örnek verecek olursak. İstenilen bir tarih aralığında stok hareketlerini listeleyecek bir raporu bu yapıdan alabilmek için şöyle bir stored procedure hazırlamalıyız.Kod:Sybase içincreate procedure dba.SP_TARIH_ARALIGINDA_STOK_HAREKETLERI(@BASLANGIC_TARIHI date,@BITIS_TARIHI date)asbeginselect TARIH=UG.GIRIS_ZAMANI,U.URUN_ADI,HAREKET_TIPI=’GIRIS’,MIKTAR=UG.GIRIS_MIKTARI fromURUN_GIRIS as UG,URUN as U whereUG.URUN_NO = U.URUN_NO and convert(date,UG.GIRIS_ZAMANI) between @BASLANGIC_TARIHI and @BITIS_TARIHI unionselect TARIH=US.SATIS_ZAMANI,U.URUN_ADI,HAREKET_TIPI=’SATIS’,MIKTAR=US.SATIS_MIKTARI fromURUN_SATIS as US,URUN as U whereUS.URUN_NO = U.URUN_NO and convert(date,US.SATIS_ZAMANI) between @BASLANGIC_TARIHI and @BITIS_TARIHI order by1 asc,2 ascendInterbase içinCREATE PROCEDURE SP_STOK_HAREKETLERI ( BASLANGIC_TARIHI DATE, BITIS_TARIHI DATE) RETURNS ( TARIH DATE, URUN_ADI CHAR(40), HAREKET_TIPI CHAR(5), MIKTAR INTEGER) ASbeginforselect UG.GIRIS_ZAMANI,U.URUN_ADI,’GIRIS’,UG.GIRIS_MIKTARI fromURUN_GIRIS UG,URUN U whereUG.URUN_NO = U.URUN_NO and cast(UG.GIRIS_ZAMANI as date) between :BASLANGIC_TARIHI and :BITIS_TARIHI unionselect US.SATIS_ZAMANI,U.URUN_ADI,’SATIS’,US.SATIS_MIKTARI fromURUN_SATIS US,URUN U whereUS.URUN_NO = U.URUN_NO and cast(US.SATIS_ZAMANI as date) between :BASLANGIC_TARIHI and :BITIS_TARIHI order by1 asc,2 ascINTO :TARIH, :URUN_ADI, :HAREKET_TIPI,:MIKTARDOSUSPEND;endBu procedure’u SQL explorer’dan çağırarak test edebilmek için şu kod yeterlidir.Kod:Sybase içinCALL DBA.SP_TARIH_ARALIGINDA_STOK_HAREKETLERI(‘2003.01.01’ , ‘2003.12.31’ )Interbase içinselect * from SP_STOK_HAREKETLERI (‘2003.01.01′,’2003.12.31’)Delphi içinden ilgili procedure’u çağırabilmek için bir Tquery’nin SQL özelliğine aşağıdaki kodu yazıp ilgili parametrelerine de gerekli değerleri atamak yeterlidir.Kod:Sybase içinDBA.SP_TARIH_ARALIGINDA_STOK_HAREKETLERI :BASLANGIC_TARIHI, :BITIS_TARIHIInterbase içinselect * from SP_STOK_HAREKETLERI (:BASLANGIC_TARIHI, :BITIS_TARIHI)Umarım bu basit örnek ile trigger ve stored procedure kullanımı konusunda yardımcı olabilmişimdir.Özetle şunu söylemek isterim ki bu tarz veritabanı tarafında olup biten hadiselerin mutlaka ama mutlaka örnekteki yöntemlerle yapılmasını öneririm. Bu şekilde yazacağınız bir stok takip ve cari takip programının stok değerlerinde ve cari değerlerinde data girişi sonucunda hata oluşma ihtimali sıfırdır. Bütün bu işlemlerin Delphi tarafında yapılması da mümkün olmakla birlikte daha fazla kod daha fazla kontrol gerektirmekte ve risk taşımaktadır. Şöyle ki bir gün tablolarınıza sizin program dışında bilgi girişi yapacak bir başka arabirim ortaya çıktığında mesela SQL Explorer’dan elle bilgi girmeniz söz konusu olduğunda stok miktarları veya cari hesaplar gelişmelerden habersiz beklemekle yetineceklerdir. Oysa bu işlemlerin veritabanı tarafında yapılması sayesinde triggerları tetiklemeyecek bir bilgi girişi olamayacağı için siz programını içinde farklı ekranlarda farklı şeyler yaparken cari hesapları tamamen unutabilirsiniz. Oraları da etkileyecek kodlar yazmakta olup olmadığınızı düşünmenize gerek yok.Sybase Adaptive Server Anywhere için tabloların, indekslerin ve referential integrity’yi sağlayacak şekilde trigger’lari oluşturacak kod:Kod:CREATE TABLE URUN (URUN_NO INTEGER NOT NULL,URUN_ADI VARCHAR(40) NOT NULL,STOK_MIKTARI INTEGER NOT NULL DEFAULT 0,PRIMARY KEY (URUN_NO) );CREATE UNIQUE INDEX XPKURUN ON URUN( URUN_NO ASC);CREATE TABLE URUN_SATIS (URUN_NO INTEGER NOT NULL,SATIS_ZAMANI DATETIME NOT NULL DEFAULT CURRENT TIMESTAMP,SATIS_MIKTARI INTEGER NOT NULL,PRIMARY KEY (URUN_NO, SATIS_ZAMANI));CREATE UNIQUE INDEX XPKURUN_SATIS ON URUN_SATIS( URUN_NO ASC, SATIS_ZAMANI ASC);CREATE INDEX XIF1192URUN_SATIS ON URUN_SATIS( URUN_NO ASC);CREATE TABLE URUN_GIRIS (URUN_NO INTEGER NOT NULL,GIRIS_ZAMANI DATETIME NOT NULL DEFAULT CURRENT TIMESTAMP,GIRIS_MIKTARI INTEGER NOT NULL,PRIMARY KEY (URUN_NO, GIRIS_ZAMANI) );CREATE UNIQUE INDEX XPKURUN_GIRIS ON URUN_GIRIS( URUN_NO ASC, GIRIS_ZAMANI ASC);CREATE INDEX XIF1191URUN_GIRIS ON URUN_GIRIS( URUN_NO ASC);CREATE TABLE URUN_STOK (URUN_NO INTEGER NOT NULL,STOK_MIKTARI INTEGER NOT NULL DEFAULT 0,PRIMARY KEY (URUN_NO));CREATE UNIQUE INDEX XPKURUN_STOK ON URUN_STOK(URUN_NO ASC);create trigger tD_URUN after DELETE on URUNreferencing old as oldrowsfor each rowbegindeclare numrows INTEGER;declare parent_delrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Parent Delete Restrict’;declare child_delrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Child Delete Restrict’;select count(*) into numrowsfrom URUN_SATISwhere URUN_SATIS.URUN_NO = oldrows.URUN_NO;if (numrows > 0) thensignal parent_delrstrct_errend if;select count(*) into numrowsfrom URUN_GIRISwhere URUN_GIRIS.URUN_NO = oldrows.URUN_NO;if (numrows > 0) thensignal parent_delrstrct_errend if;end;create trigger tU_URUN after UPDATE on URUNreferencing old as oldrows new as newrowsfor each rowbegindeclare numrows INTEGER;declare parent_updrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Parent Update Restrict’;declare child_updrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Child Update Restrict’;if oldrows.URUN_NO <> newrows.URUN_NO thenupdate URUN_SATISset URUN_SATIS.URUN_NO = newrows.URUN_NOwhere URUN_SATIS.URUN_NO = oldrows.URUN_NO;end if;if oldrows.URUN_NO <> newrows.URUN_NO thenupdate URUN_GIRISset URUN_GIRIS.URUN_NO = newrows.URUN_NOwhere URUN_GIRIS.URUN_NO = oldrows.URUN_NO;end if;end;create trigger tI_URUN_SATIS after INSERT on URUN_SATISreferencing new as newrowsfor each rowbegindeclare numrows INTEGER;declare parent_insrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Parent Insert Restrict’;declare child_insrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Child Insert Restrict’;select count(*) into numrowsfrom URUNwhere newrows.URUN_NO = URUN.URUN_NO;if (numrows = 0) thensignal child_insrstrct_errend if;end;create trigger tU_URUN_SATIS after UPDATE on URUN_SATISreferencing old as oldrows new as newrowsfor each rowbegindeclare numrows INTEGER;declare parent_updrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Parent Update Restrict’;declare child_updrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Child Update Restrict’;if oldrows.URUN_NO <> newrows.URUN_NO thenselect count(*) into numrowsfrom URUNwhere newrows.URUN_NO = URUN.URUN_NO;if (numrows = 0 ) thensignal child_updrstrct_errend if;end if;end;create trigger tI_URUN_GIRIS after INSERT on URUN_GIRISreferencing new as newrowsfor each rowbegindeclare numrows INTEGER;declare parent_insrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Parent Insert Restrict’;declare child_insrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Child Insert Restrict’;select count(*) into numrowsfrom URUNwhere newrows.URUN_NO = URUN.URUN_NO;if (numrows = 0 ) thensignal child_insrstrct_errend if;end;create trigger tU_URUN_GIRIS after UPDATE on URUN_GIRISreferencing old as oldrows new as newrowsfor each rowbegindeclare numrows INTEGER;declare parent_updrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Parent Update Restrict’;declare child_updrstrct_err EXCEPTION FOR SQLSTATE VALUE ‘Child Update Restrict’;if oldrows.URUN_NO <> newrows.URUN_NO thenselect count(*) into numrowsfrom URUNwhere newrows.URUN_NO = URUN.URUN_NO;if (numrows = 0 ) thensignal child_updrstrct_errend if;end if;end;Interbase6 için tabloların, indekslerin ve referential integrity’yi sağlayacak şekilde trigger’lari oluşturacak kod.Kod:CREATE TABLE URUN (URUN_NO INTEGER NOT NULL,URUN_ADI VARCHAR(40) NOT NULL,STOK_MIKTARI INTEGER DEFAULT 0 NOT NULL,PRIMARY KEY (URUN_NO));CREATE UNIQUE INDEX XPKURUN ON URUN( URUN_NO);CREATE TABLE URUN_GIRIS (URUN_NO INTEGER NOT NULL,GIRIS_ZAMANI DATE DEFAULT ‘now’ NOT NULL,GIRIS_MIKTARI INTEGER NOT NULL,PRIMARY KEY (URUN_NO, GIRIS_ZAMANI));CREATE UNIQUE INDEX XPKURUN_GIRIS ON URUN_GIRIS( URUN_NO, GIRIS_ZAMANI);CREATE INDEX XIF803URUN_GIRIS ON URUN_GIRIS( URUN_NO);CREATE TABLE URUN_SATIS (URUN_NO INTEGER NOT NULL,SATIS_ZAMANI DATE DEFAULT ‘now’ NOT NULL,SATIS_MIKTARI INTEGER NOT NULL,PRIMARY KEY (URUN_NO, SATIS_ZAMANI));CREATE UNIQUE INDEX XPKURUN_SATIS ON URUN_SATIS( URUN_NO, SATIS_ZAMANI);CREATE INDEX XIF804URUN_SATIS ON URUN_SATIS( URUN_NO);CREATE TABLE URUN_STOK (URUN_NO INTEGER NOT NULL,STOK_MIKTARI INTEGER DEFAULT 0 NOT NULL,PRIMARY KEY (URUN_NO));CREATE UNIQUE INDEX XPKURUN_STOK ON URUN_STOK( URUN_NO);CREATE EXCEPTION ERWIN_PARENT_INSERT_RESTRICT ‘Cannot INSERT Parent table because Child table exists.’;CREATE EXCEPTION ERWIN_PARENT_UPDATE_RESTRICT ‘Cannot UPDATE Parent table because Child table exists.’;CREATE EXCEPTION ERWIN_PARENT_DELETE_RESTRICT ‘Cannot DELETE Parent table because Child table exists.’;CREATE EXCEPTION ERWIN_CHILD_INSERT_RESTRICT ‘Cannot INSERT Child table because Parent table does not exist.’;CREATE EXCEPTION ERWIN_CHILD_UPDATE_RESTRICT ‘Cannot UPDATE Child table because Parent table does not exist.’;CREATE EXCEPTION ERWIN_CHILD_DELETE_RESTRICT ‘Cannot DELETE Child table because Parent table does not exist.’;CREATE TRIGGER tD_URUN FOR URUN AFTER DELETE ASDECLARE VARIABLE numrows INTEGER;BEGINselect count(*)from URUN_SATISwhere URUN_SATIS.URUN_NO = OLD.URUN_NO into numrows;IF (numrows > 0) THENBEGINEXCEPTION ERWIN_PARENT_DELETE_RESTRICT;ENDselect count(*)from URUN_GIRISwhereURUN_GIRIS.URUN_NO = OLD.URUN_NO into numrows;IF (numrows > 0) THENBEGINEXCEPTION ERWIN_PARENT_DELETE_RESTRICT;ENDEND !!CREATE TRIGGER tU_URUN FOR URUN AFTER UPDATE ASDECLARE VARIABLE numrows INTEGER;BEGINIF (OLD.URUN_NO <> NEW.URUN_NO) THENBEGINupdate URUN_SATISset URUN_SATIS.URUN_NO = NEW.URUN_NOwhere URUN_SATIS.URUN_NO = OLD.URUN_NO;ENDIF (OLD.URUN_NO <> NEW.URUN_NO) THENBEGINupdate URUN_GIRISset URUN_GIRIS.URUN_NO = NEW.URUN_NOwhere URUN_GIRIS.URUN_NO = OLD.URUN_NO;ENDEND !!CREATE TRIGGER tI_URUN_GIRIS FOR URUN_GIRIS AFTER INSERT ASDECLARE VARIABLE numrows INTEGER;BEGINselect count(*)from URUNwhere NEW.URUN_NO = URUN.URUN_NO into numrows;IF ( numrows = 0 ) THENBEGINEXCEPTION ERWIN_CHILD_INSERT_RESTRICT;ENDEND !!CREATE TRIGGER tU_URUN_GIRIS FOR URUN_GIRIS AFTER UPDATE ASDECLARE VARIABLE numrows INTEGER;BEGINselect count(*)from URUNwhere NEW.URUN_NO = URUN.URUN_NO into numrows;IF ( numrows = 0 ) THENBEGINEXCEPTION ERWIN_CHILD_UPDATE_RESTRICT;ENDEND !!CREATE TRIGGER tI_URUN_SATIS FOR URUN_SATIS AFTER INSERT ASDECLARE VARIABLE numrows INTEGER;BEGINselect count(*)from URUNwhere NEW.URUN_NO = URUN.URUN_NO into numrows;IF ( numrows = 0 ) THENBEGINEXCEPTION ERWIN_CHILD_INSERT_RESTRICT;ENDEND !!CREATE TRIGGER tU_URUN_SATIS FOR URUN_SATIS AFTER UPDATE ASDECLARE VARIABLE numrows INTEGER;BEGINselect count(*)from URUNwhere NEW.URUN_NO = URUN.URUN_NO into numrows;IF ( numrows = 0 ) THENBEGINEXCEPTION ERWIN_CHILD_UPDATE_RESTRICT;END