|
Trigger, Stored Procedure ve Referential Integrity
TRIGGER, STORED PROCEDURE ve REFERENTIAL INTEGRITY
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çin
Create procedure dba.SPI_URUN_GIRIS(@URUN_NO
integer,@GIRIS_MIKTARI integer)
as
begin
declare @DLR_KAYIT_SAYISI integer
select @DLR_KAYIT_SAYISI = count(*) from dba.URUN_STOK where
URUN_NO = @URUN_NO
if @DLR_KAYIT_SAYISI = 0
insert into dba.URUN_STOK(URUN_NO,STOK_MIKTARI)
values(@URUN_NO,0)
update dba.URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI+@GIRIS_MIKTARI where
URUN_NO = @URUN_NO
End;
Interbase için
CREATE PROCEDURE SPI_URUN_GIRIS ( URUN_NO INTEGER,
GIRIS_MIKTARI INTEGER) AS
DECLARE VARIABLE DLR_KAYIT_SAYISI integer;
begin
select count(*)
from URUN_STOK where URUN_NO = :URUN_NO
INTO DLR_KAYIT_SAYISI;
if (DLR_KAYIT_SAYISI=0) then
insert into URUN_STOK(URUN_NO,STOK_MIKTARI)
values(:URUN_NO,0);
update URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI+:GIRIS_MIKTARI where
URUN_NO = :URUN_NO;
End |
Delete triggerından çağıracağımız stored procedure’un adı
SPD_URUN_GIRIS olsun. Bu procedur’un kodu şu şekildedir.
Kod: |
Sybase için
Create procedure dba.SPD_URUN_GIRIS(@URUN_NO integer,
@GIRIS_MIKTARI integer)
as
begin
update dba.URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI-@GIRIS_MIKTARI where
URUN_NO = @URUN_NO
delete from dba.URUN_STOK where
URUN_NO = @URUN_NO and STOK_MIKTARI = 0
end
Interbase için
CREATE PROCEDURE SPD_URUN_GIRIS ( URUN_NO INTEGER,
GIRIS_MIKTARI INTEGER) AS
begin
update URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI-:GIRIS_MIKTARI where
URUN_NO = :URUN_NO;
delete from URUN_STOK
where URUN_NO=:URUN_NO and STOK_MIKTARI=0;
end |
Bu 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çin
call SPI_URUN_GIRIS(newrows.URUN_NO, newrows.GIRIS_MIKTARI);
Interbase için
execute 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çin
Create trigger tD_URUN_GIRIS after delete on DBA.URUN_GIRIS
referencing old as oldrows
for each row
begin
call SPD_URUN_GIRIS(oldrows.URUN_NO,oldrows.GIRIS_MIKTARI)
end
Interbase için
CREATE TRIGGER TD_URUN_GIRIS FOR URUN_GIRIS AFTER DELETE
POSITION 0 AS
BEGIN
execute procedure SPD_URUN_GIRIS OLD.URUN_NO, OLD.GIRIS_MIKTARI;
END |
Triggerlara 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çin
call SPD_URUN_GIRIS(oldrows.URUN_NO,oldrows.GIRIS_MIKTARI);
call SPI_URUN_GIRIS(newrows.URUN_NO, newrows.GIRIS_MIKTARI);
Interbase için
execute 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çin
create procedure dba.SPI_URUN_SATIS(@URUN_NO
integer,@SATIS_MIKTARI integer)
as
begin
declare @DLR_KAYIT_SAYISI integer
select @DLR_KAYIT_SAYISI = count(*) from dba.URUN_STOK where
URUN_NO = @URUN_NO
if @DLR_KAYIT_SAYISI = 0
insert into dba.URUN_STOK(URUN_NO,STOK_MIKTARI)
values(@URUN_NO,0)
update dba.URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI-@SATIS_MIKTARI where
URUN_NO = @URUN_NO
end
create procedure dba.SPD_URUN_SATIS(@URUN_NO integer,
@SATIS_MIKTARI integer)
as
begin
update dba.URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI+@SATIS_MIKTARI where
URUN_NO = @URUN_NO
delete from dba.URUN_STOK where
URUN_NO = @URUN_NO and STOK_MIKTARI = 0
end
Interbase için
CREATE PROCEDURE SPI_URUN_SATIS ( URUN_NO INTEGER,
SATIS_MIKTARI INTEGER) AS
DECLARE VARIABLE DLR_KAYIT_SAYISI integer;
begin
select count(*)
from URUN_STOK where URUN_NO = :URUN_NO
INTO DLR_KAYIT_SAYISI;
if (DLR_KAYIT_SAYISI=0) then
insert into URUN_STOK(URUN_NO,STOK_MIKTARI)
values(:URUN_NO,0);
update URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI-:SATIS_MIKTARI where
URUN_NO = :URUN_NO;
End
CREATE PROCEDURE SPD_URUN_SATIS ( URUN_NO INTEGER,
SATIS_MIKTARI INTEGER) AS
begin
update URUN_STOK set
STOK_MIKTARI = STOK_MIKTARI+:SATIS_MIKTARI where
URUN_NO = :URUN_NO;
delete from URUN_STOK
where URUN_NO=:URUN_NO and STOK_MIKTARI=0;
end |
Sybase 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_SATIS
referencing old as oldrows
for each row
begin
call 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 AS
BEGIN
execute procedure SPD_URUN_SATIS OLD.URUN_NO, OLD.SATIS_MIKTARI;
END |
Interbase 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çin
create procedure
dba.SP_TARIH_ARALIGINDA_STOK_HAREKETLERI(@BASLANGIC_TARIHI
date,@BITIS_TARIHI date)
as
begin
select
TARIH=UG.GIRIS_ZAMANI,U.URUN_ADI,HAREKET_TIPI='GIRIS',MIKTAR=UG.GIRIS_MIKTARI
from
URUN_GIRIS as UG,URUN as U where
UG.URUN_NO = U.URUN_NO and convert(date,UG.GIRIS_ZAMANI)
between @BASLANGIC_TARIHI and @BITIS_TARIHI union
select
TARIH=US.SATIS_ZAMANI,U.URUN_ADI,HAREKET_TIPI='SATIS',MIKTAR=US.SATIS_MIKTARI
from
URUN_SATIS as US,URUN as U where
US.URUN_NO = U.URUN_NO and convert(date,US.SATIS_ZAMANI)
between @BASLANGIC_TARIHI and @BITIS_TARIHI order by
1 asc,2 asc
end
Interbase için
CREATE PROCEDURE SP_STOK_HAREKETLERI ( BASLANGIC_TARIHI DATE,
BITIS_TARIHI DATE) RETURNS ( TARIH DATE, URUN_ADI CHAR(40),
HAREKET_TIPI CHAR(5), MIKTAR INTEGER) AS
begin
for
select UG.GIRIS_ZAMANI,U.URUN_ADI,'GIRIS',UG.GIRIS_MIKTARI
from
URUN_GIRIS UG,URUN U where
UG.URUN_NO = U.URUN_NO and cast(UG.GIRIS_ZAMANI as date)
between :BASLANGIC_TARIHI and :BITIS_TARIHI union
select US.SATIS_ZAMANI,U.URUN_ADI,'SATIS',US.SATIS_MIKTARI
from
URUN_SATIS US,URUN U where
US.URUN_NO = U.URUN_NO and cast(US.SATIS_ZAMANI as date)
between :BASLANGIC_TARIHI and :BITIS_TARIHI order by
1 asc,2 asc
INTO :TARIH, :URUN_ADI, :HAREKET_TIPI,:MIKTAR
DO
SUSPEND;
end |
Bu procedure’u SQL explorer’dan çağırarak test edebilmek için şu kod
yeterlidir.
Kod: |
Sybase için
CALL DBA.SP_TARIH_ARALIGINDA_STOK_HAREKETLERI('2003.01.01' ,
'2003.12.31' )
Interbase için
select * 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çin
DBA.SP_TARIH_ARALIGINDA_STOK_HAREKETLERI :BASLANGIC_TARIHI,
:BITIS_TARIHI
Interbase için
select * 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 URUN
referencing old as oldrows
for each row
begin
declare 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 numrows
from URUN_SATIS
where URUN_SATIS.URUN_NO = oldrows.URUN_NO;
if (numrows > 0) then
signal parent_delrstrct_err
end if;
select count(*) into numrows
from URUN_GIRIS
where URUN_GIRIS.URUN_NO = oldrows.URUN_NO;
if (numrows > 0) then
signal parent_delrstrct_err
end if;
end;
create trigger tU_URUN after UPDATE on URUN
referencing old as oldrows new as newrows
for each row
begin
declare 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 then
update URUN_SATIS
set URUN_SATIS.URUN_NO = newrows.URUN_NO
where URUN_SATIS.URUN_NO = oldrows.URUN_NO;
end if;
if oldrows.URUN_NO <> newrows.URUN_NO then
update URUN_GIRIS
set URUN_GIRIS.URUN_NO = newrows.URUN_NO
where URUN_GIRIS.URUN_NO = oldrows.URUN_NO;
end if;
end;
create trigger tI_URUN_SATIS after INSERT on URUN_SATIS
referencing new as newrows
for each row
begin
declare 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 numrows
from URUN
where newrows.URUN_NO = URUN.URUN_NO;
if (numrows = 0) then
signal child_insrstrct_err
end if;
end;
create trigger tU_URUN_SATIS after UPDATE on URUN_SATIS
referencing old as oldrows new as newrows
for each row
begin
declare 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 then
select count(*) into numrows
from URUN
where newrows.URUN_NO = URUN.URUN_NO;
if (numrows = 0 ) then
signal child_updrstrct_err
end if;
end if;
end;
create trigger tI_URUN_GIRIS after INSERT on URUN_GIRIS
referencing new as newrows
for each row
begin
declare 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 numrows
from URUN
where newrows.URUN_NO = URUN.URUN_NO;
if (numrows = 0 ) then
signal child_insrstrct_err
end if;
end;
create trigger tU_URUN_GIRIS after UPDATE on URUN_GIRIS
referencing old as oldrows new as newrows
for each row
begin
declare 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 then
select count(*) into numrows
from URUN
where newrows.URUN_NO = URUN.URUN_NO;
if (numrows = 0 ) then
signal child_updrstrct_err
end 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 AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from URUN_SATIS
where URUN_SATIS.URUN_NO = OLD.URUN_NO into
numrows;
IF (numrows > 0) THEN
BEGIN
EXCEPTION ERWIN_PARENT_DELETE_RESTRICT;
END
select count(*)
from URUN_GIRIS
where
URUN_GIRIS.URUN_NO = OLD.URUN_NO into numrows;
IF (numrows > 0) THEN
BEGIN
EXCEPTION ERWIN_PARENT_DELETE_RESTRICT;
END
END !!
CREATE TRIGGER tU_URUN FOR URUN AFTER UPDATE AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
IF (OLD.URUN_NO <> NEW.URUN_NO) THEN
BEGIN
update URUN_SATIS
set URUN_SATIS.URUN_NO = NEW.URUN_NO
where URUN_SATIS.URUN_NO = OLD.URUN_NO;
END
IF (OLD.URUN_NO <> NEW.URUN_NO) THEN
BEGIN
update URUN_GIRIS
set URUN_GIRIS.URUN_NO = NEW.URUN_NO
where URUN_GIRIS.URUN_NO = OLD.URUN_NO;
END
END !!
CREATE TRIGGER tI_URUN_GIRIS FOR URUN_GIRIS AFTER INSERT AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from URUN
where NEW.URUN_NO = URUN.URUN_NO into numrows;
IF ( numrows = 0 ) THEN
BEGIN
EXCEPTION ERWIN_CHILD_INSERT_RESTRICT;
END
END !!
CREATE TRIGGER tU_URUN_GIRIS FOR URUN_GIRIS AFTER UPDATE AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from URUN
where NEW.URUN_NO = URUN.URUN_NO into numrows;
IF ( numrows = 0 ) THEN
BEGIN
EXCEPTION ERWIN_CHILD_UPDATE_RESTRICT;
END
END !!
CREATE TRIGGER tI_URUN_SATIS FOR URUN_SATIS AFTER INSERT AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from URUN
where NEW.URUN_NO = URUN.URUN_NO into numrows;
IF ( numrows = 0 ) THEN
BEGIN
EXCEPTION ERWIN_CHILD_INSERT_RESTRICT;
END
END !!
CREATE TRIGGER tU_URUN_SATIS FOR URUN_SATIS AFTER UPDATE AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
select count(*)
from URUN
where NEW.URUN_NO = URUN.URUN_NO into numrows;
IF ( numrows = 0 ) THEN
BEGIN
EXCEPTION ERWIN_CHILD_UPDATE_RESTRICT;
END
END !! |
bimeks borland component database delphi delphi.net delphi dersleri firebird help interbase makale oracle
seminer software sybase veritabanı web
|
|
|