Hurriyet

PLSQL etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
PLSQL etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

19 Şubat 2014 Çarşamba

PL/SQL: Dynamic SQL - Dinamik SQL

Dinamik SQL Nedir?

Dinamik SQL'ler; içerlerindeki sütun dataları değişen, ya da farklı koşullar altında veriler çıkartan SQL'lerdir. Bunlar çalıştırıldığında sütun içerisindeki değişikliklere göre sonuçları yansıtmaktadır. 

Dinamik SQL ile DDL,DCL veya DML ifadeleri yazılabilir ve PL/SQL'den çalıştırılabilinirler. 

PL/SQL içerisinde izin verilen SQL ifadeleri  SELECT; INSERT, UPDATE, DELETE, MERGE, COMMIT ve ROLLBACK'tir. 

Programda içerisinde bulunmayan ve çalıştırılma zamanında oluşturulan SQL'lere dinamik SQL'ler deriz. Bunlar çalışma anında oluşturulduğu için PL/SQL değişkenleri kullanabilirler ve çalıştırabilirler. Dinamik SQL'lerin text'leri çalıştırılma anlarına kadar bilinmeyebilirler. O yüzden PL/SQL programının çalıştırılması beklenir. Yani programın derlenmesini değil çalıştırılmasını beklerler. 

Program içerisinde oluşturduğumuz dinamik SQL'leri "execute immediate" ile hemen çalıştırabiliriz. 

Dinamik SQL Örneği:

 CREATE OR REPLACE PROCEDURE create_table(  
  p_table_name VARCHAR2, p_col_specs VARCHAR2) IS  
 BEGIN  
  EXECUTE IMMEDIATE 'CREATE TABLE ' || p_table_name ||  
           ' (' || p_col_specs || ')';  
 END;  
 /  

Bu örnekte prosedürümüzle bir tablo yaratmaktayız. Prosedürün derlenmesi sırasında gerekli veriler belirli olmadığı için dinamik SQL kullanırız.

 BEGIN  
  create_table('EMPLOYEE_NAMES',  
    'id NUMBER(4) PRIMARY KEY, name VARCHAR2(40)');  
 END;  
 /  

Prosedür tanımlandıktan sonra da çalıştırdığımız içindeki veriler çalıştırılma anında kullanılır. Çalıştırılma anında o veriler ile istediğimiz SQL tanımlanır. Dinamik SQL'imizin içine tablo adını ve sütunlarla ilgili bilgileri göndeririz. SQL oluşturulunca da hemen "execute immediate" ifadesi ile çalıştırılır.


18 Şubat 2014 Salı

PL/SQL: Stored Functions - Fonksiyonlar

Stored Function dediğimiz nesneler aslında değer döndüren adlandırılmış PL/SQL fonksyionlarıdır. Fonksiyonlarla genelde bir değer hesaplanmaktadır.

Procedure ile Function  Arasındaki Farklar:
Procedure’lar PL/SQL ifadesi olarak çalıştırılırlar.
Function’lar bir ifadenin bir parçası olarak çalıştırılırlar.
Procedure’lar başlık kısımlarında bir return ifadesi taşımazlar.
Function’lar başluık kısımlarında mutlaka bir return ifadesi içermelidirler.
İstenirse output değerleri taşıyabilirler.
Sadece bir değer geri döndürebilirler.
İçerlerinde bir return ifadesi bulunsada bir değer döndürmek zorunda değildirler.
İçerisinde mutlaka return ifadesi bulunmalıdır.

Not:Procedure'larda bir out ifadesi bulunuyorsa bu procedure'ın fonksiyona çevrilerek yazılması Oracle tarafından tavsiye edilmektedir.

Fonksiyon Örneği:

 create or replace function deneme(x int)  
 return int as a int;  
 begin  
   
 a:=x+5;  
 return a;  
 end deneme;  
 /  

Bu fonksiyon örneğimizde tek değişken alan ve yine tek değişken döndüren bir program yazmış durumdayız.

declare   
 c int;  
 begin   
 c:=deneme(10);  
 dbms_output.put_line(c);  
 end;  

Bu fonksiyonumuzu sonra yukarıdaki gibi bir PL/SQL bloğu içerisinde çağırdığımızda, fonksiyonun geri döndürdüğü değeri bir değişkene atıp onu bastırırız. Sonuç olarak fonksiyonumuzun içerisine 10 sayısını gönderip, bu c değişkenine 15 değeri atanıp geri döndürülür.

PL/SQL'de Direkt Olarak Fonksiyonun Kullanılması:

 variable maas number;  
 execute :maas := deneme(100);  

Burada maas diye bir değişken tanımladıktan sonra deneme fonksiyonumuza bir değer gönderip bu fonksiyonumuzu çalıştırtabiliriz. Sonrasında çıkacak sonucu görmek için "Print maas" diyebiliriz.

Fonksiyonun Avantajları:

1-Fonksiyonlarla SQL ifadelerinin yapabileceği şeyler arttırılabilinir.
2-Data değerleri değiştirilebilinir.
3-Çok karışık işlemler halledilebilinir.

Fonksiyonun SQL İfadesinde Kullanılmasıyla İlgili Bir Örnek:

 CREATE OR REPLACE FUNCTION vergi(x NUMBER)  
  RETURN NUMBER IS  
 BEGIN  
   RETURN (x * 0.08);  
 END tax;  
 /  
 SELECT id,isim,maas, vergi(maas)  
 FROM  calisanlar  
 WHERE dep_no = 100; 

Burada calisanlar adlı tablomuzu sorgularken vergi hesaplaması yapmak için yukarıda yazdığımız fonksyionu kullanırız. Bu şekilde hem modülerliğimizi arttırmış oluruz, hem de kompleksliği azaltmış oluruz.

Fonksiyon Silmek İçin:

 drop function fonksiyon_ismi  



PL/SQL: Parametre Modları - Parameter Modes

PL/SQL prosedürlerinde veya programlarında parametreler 3 tipte olabilirler. Bunlar

1-IN
2-OUT
3-IN OUT

IN: parametre tipi programımıza bir değer göndermektedir. Standart parametre modudur.. Parametre tipi herhangi bir ifade, değer veya sabit olabilir.

OUT: parametre tipi programımızdan bir değeri ortama geri döndürmektedir.  Özellikle belirtilmesi gerekir. Bir değişken olmalıdır.

IN OUT: parametre tipi programa bir değer gönderirken bu değerin değiştirilme ihtimali ve geri döndürülme ihtimali bulunur.  Özellikle belirtilmesi gerekir. Bir değişken tipinde olmalıdır.

Prosedürler çağırılırken içerisindeki değerler direk in tipi parametre olarak kabul edilirler. Eğer prosedürümüzün bir değer döndüreceğini belirtmek istiyorsak özellikle out veya in out diye belirtmemiz gerekir.

Standart bir PL/SQL blok örneği:

 create or replace procedure (id int,x number)  
 begin  
 ......  
 end;  
 / 

Yukarıdaki örneğimizde de görüldüğü gibi id ve x parametreleri direk olarak in tipi parametre modunda yaratılır. Özellikle belirtmemiz gerekmez.

Basit Örnek:

 create or replace procedure deneme( x int, y int)  
 is  
   
 begin  
 dbms_output.put_line(sysdate);  
 end;  
 /  
   
 execute deneme(5,10); 

Yukarıdaki örnekte parametrelerimizi verdikten sonra prosedürümüzün çalıştırılmasını gösterdik. Sonuçlarını Toad kullanıyorsak eğer DBMS OUTPUT tabından görebiliriz.


OUT Parametre Tipinin Kullanımına Örnek:

 create or replace procedure deneme( x int, y int,z out int)  
 is  
 begin  
 z:=x*y;  
 end;  
 /  

Yukarıdaki örneğimizde bir parametre tipimizin değerini out olarak belirlemiş durumdayız. Bu prosedürümüzde sadece verilen ilk 2 değeri çarpıp  z değişkenine eşitliyoruz. Sonrasında bu prosedürümüzü çalıştıran programımızı yazıyoruz.

 declare   
 a int;  
 begin  
 deneme(5,10,a);  
  dbms_output.put_line(a);  
  end;/

Bu programımızda ise yukarıda yazdğımız prosedür çağrılmaktadır. İlk 2 değer sabit olarak verilmiş olup, 3. değer değişken olarak verilmiştir. O değişkene ilk 2 değerin çarpımı atandıktan sonrada bu değer dbms_output.put_line ile yazdırılmıştır.

IN OUT Parametre Tipinin Kullanımına Örnek:

 create or replace procedure deneme( x int, y int,z in out int)  
 is  
 begin  
 z:=(x*y)+z;  
 end; 

Bu prosedürümüzde de z değişkenimizi in out olarak belirtmekteyiz. Bu şekilde prosedürümüzün içerisine belirli bir değer koyup bu değeri program içinde değiştirip geri alabiliriz.

 declare   
 a int ;  
 begin  
 a:=5;  
 deneme(5,10,a);  
  dbms_output.put_line(a);  
  end;/  

Bu programımızda da prosedürümüzün içine gönderdiği a değişkenin değeri 5 iken , program içerisinde bunu a=5*10+5 olarak görürüz."a"'nını değeri artık 55'tir. Bu şekilde de görmüş olduğumuzu üzere parametremizin değerini içeride değiştirip almış olduk.

SQL*Plus'ta Değişken Tanımlamak:

Yukarıdaki gibi eğer program yazmıyıp, sadece prosedürümüzü execute edip sonuçlarını görmek istersek aşağıdaki gibi değişken tanımlayabiliriz.

 create or replace procedure deneme( x out int)  
 is  
 begin  
 x:=5;  
   
 end;  
 /  

Prosedürümüzü yukarıdaki gibi tanımladıktan sonra değişkenimizi "VARIABLE" ifadesiyle tanımlayıp "PRINT" ifadesiyle sonucunu görebiliriz.

 variable a number  
  execute deneme(:a);  
  print a; 

Prosedürlerin İçerisindeki Değerleri Direkt Olarak Göndermek:

 create or replace procedure deneme( x int, y int)  
 is  
   
 begin  
 dbms_output.put_line(x*y);  
 end;  
 /  
   
 execute deneme(5,10); 

Yukarıdaki örneğimizi düşündüğümüzde "Execute deneme(5,10)"  dediğimizde, 5 sayısı x'e atanırken, y sayısına 10 değeri atanmaktadır. Eğer biz bunu değiştirmek istersek "execute deneme(y=>5,x=>10) şeklinde bir değer atama işlemi yapabiliriz.

29 Ocak 2014 Çarşamba

PL/SQL: Exception - Hata Yönetimi - PL/SQL Debuging - Handling PL/SQL Errors - PL/SQL Debuging

PL/SQL procedure'lari içerisindeki run-time hataları dizayn yanlışlıkları, donanım bozuklukları veya kodlama hataları gibi bir sürü nedenden dolayı ortaya çıkmaktadır. Bütün olabilecek hataları tahmin edemesek de, karşımızı çıkabileceklerini düşündüğümüz hataları işleyebiliriz.

Eğer programımızda hata kontrolü yoksa programın çalışması durur ve programın kontrolü işletim sistemine döner. Hata kontrolü varsa da program hatalara rağmen devam edebilir.

Exception Nedir?

 PL/SQL'de bir warning veya error durumunun ortaya çıkması "exception" olarak tanımlanır. Exception'lar ya kullanıcılar tarafından ya da sistem tarafından tanımlanırlar. Kullanıcı tarafından tanımlanan hatalar "raise" ifadesiyle başlatılırlar.

Çıkan hataları yönetmek için exception blokları yazarız. Exception ortaya çıktığında çalışma durup o bloğu kapsayan exception bloğuna gider.

Aşağıdaki örneğimizde standart bir hata bloğu tanımlamaktayız. Bu hata bloğunda tarih bilgisi çekilip tarih tablomuzun tek sütununa ekleriz. Eğer hata olursa da o ifadeyi kapsayan begin bloğundaki exception kısmına giderek oradaki hatalar arasından arama yapar. Örneğimizdeki hata diğer bütün hataları kapsadığı için eğer hata çıkarsa hemen o kısma girer ve rollback eder.

 DECLARE  
   a date;  
 BEGIN  
   select sysdate into a from dual;  
   insert into tarih values(a);  
   COMMIT;  
 EXCEPTION   
   WHEN OTHERS THEN  
    ROLLBACK;  
 END; 

Önceden Tanımlı PL/SQL Exception'ları:

Sistem tarafından tanımlı hatalar ne zaman PL/SQL de bir hata olursa, o zaman tetiklenirler. Oracle hatalarının hepsinin bir hata numarası vardır; ancak bu hatalar adlarıyla kontrol edilirler.

Genel olarak ortaya çıkacak hataları "OTHERS" ifadesiyle kapsayabiliriz. Hatalar ortaya çıktığında SQLCODE ve SQLERRM fonksiyonları işimize yarayabilir. SQLCODE fonksiyonu SQL hata numarasını verirken, SQLERRM ise SQL hata mesajını vermektedir.

Ayrıca diğer adı olmayan hataları işlemek için  "pragma exception init" ifadesini kullanabiliriz. Aşağıdaki hatalar hata koduna tanımlı isim  verilmiş olan hatalardır.

ExceptionOracle Hata KoduSQLCODE Değeri

ACCESS_INTO_NULL

ORA-06530

-6530

CASE_NOT_FOUND

ORA-06592

-6592

COLLECTION_IS_NULL

ORA-06531

-6531

CURSOR_ALREADY_OPEN

ORA-06511

-6511

DUP_VAL_ON_INDEX

ORA-00001

-1

INVALID_CURSOR

ORA-01001

-1001

INVALID_NUMBER

ORA-01722

-1722

LOGIN_DENIED

ORA-01017

-1017

NO_DATA_FOUND

ORA-01403

+100

NOT_LOGGED_ON

ORA-01012

-1012

PROGRAM_ERROR

ORA-06501

-6501

ROWTYPE_MISMATCH

ORA-06504

-6504

SELF_IS_NULL

ORA-30625

-30625

STORAGE_ERROR

ORA-06500

-6500

SUBSCRIPT_BEYOND_COUNT

ORA-06533

-6533

SUBSCRIPT_OUTSIDE_LIMIT

ORA-06532

-6532

SYS_INVALID_ROWID

ORA-01410

-1410

TIMEOUT_ON_RESOURCE

ORA-00051

-51

TOO_MANY_ROWS

ORA-01422

-1422

VALUE_ERROR

ORA-06502

-6502

ZERO_DIVIDE

ORA-01476

-1476

Özetle yukarıdaki tanımlı hatalarımız olabileceğini öngörüyorsak "exception when ..... then" boşluğuna o tanımlı hata ismini vererek o hatayı işleyebiliriz.

PL/SQL Hatalarını Tanımlamak:

PL/SQL'de kendi hatalarımızı tanımlayabiliriz. Yukarıdaki hatalar dışında karşımıza çıkabilecek olanları kendimiz tanımlayarak bunların işlenmesini sağlayabiliriz. Bu hatalar değişken tanımlama kısmında tanımlanırlar. Örnek olarak aşağıdaki tanımı verebiliriz.

Declare
  hata exception;

PL/SQL Hatalarını Bir SQL Hata Numarasıyla Eşleştirmek: 

Hataların bir isimle eşleştirilmesi için "pragma exception_init(exception_ismi,-Oracle_hata_numarası;" şeklinde bir ifade kullanmalıyız.

 Declare  
  hata exception;  
  pragma exception_init(hata,-60);  
 Begin  
  --"hata"'ya neden olabilecek işlemler  
 Exception  
  When hata then  
  Rollback;  
 End;  

Yukarıdaki örnekte ORA-00060 olan deadlock hatası gerçekleştiğinde bu hatayı bize "hata" olarak bir uyarı diye gösterecektir.

Programda Kendi PL/SQL Hatalarımızı Yaratmak:

RAISE_APPLICATION_ERROR procedure'ı ile kendi ORA- hatalarımızı yaratabiliriz. Bu şekilde bir hata olmasa bile, bizim iş akışımıza uygun olmayan bir durum yakaladığımızda programı durdurup uygulamaya mesaj gönderebiliriz. Burada hata numarası olarak verebileceğimiz sayı -20000 ile -20999 arasında olabilir. Hata mesajı da 2048 bytes uzunluğunda olabilir.

 Declare  
    
 Begin  
  --"hata"'ya neden olabilecek işlemler  
 raise_application_error(-20001,'Dikkat!!');
 End;  

Yukarıdaki durumda program çalıştığında uyarı amaçlı bir ifade çalıştırmaktayız. İşlemlerimiz bir ORA hatasına neden olmasa da, kendimiz programımızı bu şekilde durdurabiliriz.

RAISE İfadesiyle Exception Üretmek:

Yukarıdaki başlığımızda nasıl exception üretebileceğimizi gördük. Bu exception işlemek istediğimizde "raise" ifadesini kullanabiliriz.  Bunun için ilk önce kendi hatamızı tanımlamamız gerekir.

DECLARE  
  stok_hatası exception;  
  stok number(5);  
 BEGIN  
   select sayı into stok from depo;  
   IF stok< 100 THEN  
    RAISE stok_hatası;  
   END IF;  
 EXCEPTION  
   WHEN stok_hatası THEN  
    raise_application_error(-20001,"Stok kalmamış durumdadır");  
 END;  

Örneğimizde ilk önce stok_hatası şeklinde hatamızı tanımlamaktayız. Sonra uygun zaman geldiği zaman eğer şartlar sağlanıyorsa stok_hatası şeklinde hatamız tetiklenir. Bu hata tetiklendiği zaman programın ne yapması gerektiğini exception bloğunda tanımlarız. Örneğimizde bunu raise_application_error procedure'u ile işlemekteyiz. Bu şekilde kısaca eğer hatayla karşılaşırsak bize "Stok kalmamıştır" şeklinde uyarı verecektir.

Bu şekilde kendi yarattığımız hatayı işlemiş oluruz.

Loop İçerisine Exception Tanımlamak:

Loop içerisine Exception tanımlama örneğimiz için aşağıdaki synoynm compile etme örneğimize bakabiliriz. Bu örnekte görebileceğimiz gibi exception tanımlayabilmemiz için, exception'ın ait olduğu bir begin end bloğu olmalıdır. Loop içerisinde begin.. end bloğu koyarak içeride yaşanabilecek herhangi bir hatanın farkında olabiliriz.

 declare  
 cursor a is select owner,object_name from dba_objects where object_type='SYNONYM' and status='INVALID' and owner!='PUBLIC';  
 z varchar2(100);  
 begin  
 for x in a  
 loop  
   
 begin  
 z:= 'alter synonym '|| x.owner || '.'|| x.object_name || ' compile;';  
 execute immediate z;  
 exception when others  
 then   
 dbms_output.put_line(SQLERRM || ' ' ||SQLCODE || ' ' || x.object_name);  
 end;  
 end loop;  
   
   
 end;  
 / 





14 Ocak 2014 Salı

Oracle Veritabanı: Trigger'lar - Trigger Nedir? - Triggers - What are Triggers?

Trigger'lar insert, update ve delete ifadelerinden sonra çalıştırılan procedure'lardır. Bunlar tablolar üzerinde tanımlanırlar. Trigger'lar SQL ve PL\SQL ifadelerini içerebilirler ve diğer PL\SQL birimlerini çağırabilirler. Veritabanında saklanırlar. Belirli durumlarda çağırılırlar.

Trigger'ların procedurelardan farkı; trigger'lar Oracle tarafından tetiklenirken procedure'lar başka trigger'lar, application'lar veya kullanıcı tarafından çalıştırılabilirler.

Trigger'lar veritabanında tablolardan farklı bir yerde tutulurlar. Sadece tablolar üzerinde tanımlanabilirler. View'lar üzerine tanımlanamasalarda, view'ların üzerinde bir değişiklik yapılmaya çalışıldığında view'ın üzerine tanımlandığı tablolarda kaydedilmiş trigger'lar çalıştırılır.

Trigger'ın Tetiklendiği Durum Tipleri:

Herhangi bir DML(Data Manipulation Language) ifadesi : INSERT, UPDATE, DELETE
Herhangi bir DDL(Data Definition Language) ifadesi: CREATE, ALTER, DROP
Herhnagi bir veritabanı işleminde: Örnek olarak Logon, Logoff, Startup, Shutdown işleminde.

Trigger'ların Kullanım Amaçları: 

Trigger'lar ile DML ifadelerinin kullanımı kısıtlanabilir. Normalde bunun için role ve yetkiler kullanılırken, trigger'lar ile kullanıcının adına bakılmaksızın tablolar üzerine giriş çıkışlar kısıtlanır ve değişiklik yapılması düzenlenir.

Trigger'ların diğer genel kullanım alanlar:

-Otomatik olarak ilgili sütunlar için değerler üretmesi
-Uygun olmayan transaction'ları engellemek için
-Güvenlik katmanı oluşturmak için
-Loglama yapmak için
-Yapılan işlemlerle ilgili kayıt oluşturmak için
-Tablolar arasında eşleme ve eşitleme yapmak için
-Tablo erişimiyle ilgili bilgiler toplamak için

Not: Transaction Nedir?
Transaction olarak belirttiğimiz sorgular ya DML ifadeleridir ya da DDL ifadeleridir. DDL ifadeleri gönderildiğinde otomatik olarak commit edilirken, DML ifadeleri gönderildiğinde ertesinde commit veya rollback sorgularıda gönderilmelidirler ki transaction bitsin.

Trigger'lar ve Constraint'ler(Kısıtlar):

Kısıtlarda tablo içerisindeki veriler düzenlenir ve gelecek olan transactionlarda kısıtlar uygulanır. Yani tablo içerisindeki bütün verilerin ve gelecekde girilecek verilerin constraint'lere uygun olabilieceğini söyleyebiliriz.  Bir tabloya kısıt koyulduğunda içerideki datalarında buna uygun olması gerekir. Öte yandan trigger'lar tanımlandıkları zaman tablo içerisindeki verileri kontrol etmezler. Sadece sonradan girilen verileri kontrol ederler ve buna göre içerilerindeki kodları çalıştırırlar.

Trigger Zamanlama Tipleri:

1-Before: Trigger içerisindeki işlemler tablo üzerine gerçekleşecek işlemden önce çalışır.
2-After: Trigger yapılan işlemden sonra çalışır.
3-Instead of: SQL ifadesi yerine Trigger'ın içerisindeki ifadeler çalıştırılır. Bu işlem genelde view'lar üzerine işlem yapmak istendiğinde kullanılır. Böylece view'a ulaşılmak istendiğinde aslında onu oluşturan tablolar oluşturulur.

Statement Level Triggers ve Row Level Triggers:


Statement Level Triggers
Row Level Triggers
Standart Trigger tipidir.
“For Each Row” ifadesini kullanır.
Triggerı çalıştıran durum için çalıştırılır. Yani  eğer update,delete veya insert ifadesi birden fazla satırı değiştirse bile, trigger bir kere çalışır.
Row level trigger’da update,delete veya insert ifadelerinden herhangi birisinin değiştirdiği her satır için trigger çalıştırılır.
Herhangi bir değişikliğe neden olmasa da bir kere çalıştırılır.
Her hiçbir değişikliğe neden olmıyorsa tetiklenmez.

Trigger'ların Kısımları:

Bir trigger'ın basitçe 3 tane kısmı vardır. 
1-Trigger'ın hangi tablo üzerinde ne zaman çalışacağını gösteren kısım.
2-Trigger kısıtı - Ne zaman tetikleneceğini gösteren kısım.
3-Trigger aksiyonu - Bütün koşullar oluştuğunda trigger'ın hangi işlemleri yapacağını gösteren bölüm.

1-Trigger Olayı:

Trigger'ın çalışmasını  sağlayan ilk kısımdır. Burada hangi tablonun hangi sütununun üzerine tanımlı olduğu ve DML ifadesinin öncesinde mi sonrasında mı çalışacağını tanımlarız. 

Genel ifade:

[AFTER|BEFORE] [INSERT|UPDATE|DELETE] OF [KOLON_ADI] ON [TABLO_ADI]

Update ifadesinde birden fazla kolon adı belirtilebilinirken delete ve insert ifadelerinde bütün satır etkilendiği için tek bir kolon adı verilebilinir.

2- Trigger Kısıtı:

Trigger kısıtlarında boolean bir ifade verilir. Bu ifade doğru olduğunda ancak devamındaki kod çalıştırılır. 

WHEN (trigger_kısıt =true) 

3- Trigger Aksiyonu:

Trigger aksiyonu içinde SQL ifadeleri içeren bir PL\SQL procedure'udür. Trigger tetiklendikten ve trigger kısıtı doğru çıktıktan sonra trigger aksiyonu çalıştırılır. 

Koşullu İfadeler:

Koşullu ifadeler olarak belirttiğimiz anahtar kelimeler birden fazla trigger tipi kullanıldığı zaman işe yarayabilirler. Örnekte belirttiğimiz trigger birden fazla durumda(insert,update,delete) tetikleneceği için bunları ayırmak için içerisinde "DELETING", "INSERTING" veya "UPDATING" ifadelerinin kullanılması gerekir.


 CREATE OR REPLACE TRIGGER secure_emp BEFORE  
 INSERT OR UPDATE OR DELETE ON employees   
  BEGIN  
   IF (TO_CHAR(SYSDATE,'DY') IN ('SAT','SUN')) OR  
     (TO_CHAR(SYSDATE,'HH24')   
     NOT BETWEEN '08' AND '18') THEN  
    IF DELETING THEN RAISE_APPLICATION_ERROR(  
     -20502,'You may delete from EMPLOYEES table'||  
     'only during normal business hours.');  
    ELSIF INSERTING THEN RAISE_APPLICATION_ERROR(  
     -20500,'You may insert into EMPLOYEES table'||   
     'only during normal business hours.');  
    ELSIF UPDATING ('SALARY') THEN  
     RAISE_APPLICATION_ERROR(-20503, 'You may '||     'update SALARY only normal during business hours.');  
    ELSE RAISE_APPLICATION_ERROR(-20504,'You may'||  
     ' update EMPLOYEES table only during'||  
     ' normal business hours.');  
    END IF;  
   END IF;  
  END; 


DML Trigger Örneği:

Dml trigger'ımızda yaptığımız işleme göre trigger insert veya update işlemlerinde tetiklenmektedir. Tetiklendiğinde de tetikleyen ifadenin etkilediği bütün satırlar için belirli şartlara göre trigger içinde sorgular çalışır. Eğer belirleyen şartlara uymazsa hata verir. Raise_application_error çalıştığında içinde bulunduğu blok biter ve o blok hata döndürür.


 CREATE OR REPLACE TRIGGER restrict_salary  
 BEFORE INSERT OR UPDATE OF salary ON employees  
 FOR EACH ROW  
 BEGIN  
  IF NOT (:NEW.job_id IN ('AD_PRES', 'AD_VP'))  
    AND :NEW.salary > 15000 THEN  
   RAISE_APPLICATION_ERROR (-20202,  
    'Employee cannot earn more than $15,000.');  
  END IF;  
 END;/ 

OLD ve NEW Belirteçleri:


DML ifadeleri
:OLD
:NEW
Insert
Null
Yeni girilen değer
Update
Update yapılmadan önceki değer
Yeni update edilen değer
Delete
Silinmeden önceki değer
Null

OLD ve NEW Belirteç Örneği:

Burada verilen örnekte employees adlı tabloya yapılan her giriş için bu tabloyla ilgili loglama yapan tabloya yani audit_emp'e değerler girilir.


CREATE OR REPLACE TRIGGER audit_emp_values  
 AFTER DELETE OR INSERT OR UPDATE ON employees  
 FOR EACH ROW  
 BEGIN  
  INSERT INTO audit_emp(user_name, time_stamp, id,  
   old_last_name, new_last_name, old_title,  
   new_title, old_salary, new_salary)  
  VALUES (USER, SYSDATE, :OLD.employee_id,  
   :OLD.last_name, :NEW.last_name, :OLD.job_id,  
   :NEW.job_id, :OLD.salary, :NEW.salary);  
 END;  
 /  
   

Trigger'larda When ifadesi:

Trigger'lardaki when ifadesi trigger'ın çalışmasıyla ilgili bir koşul olarak kullanılabilir. Böylece her satır için trigger çalıştırıldığında trigger'ın içindeki ifadelerin uygulanıp uygulanmayacağını belirler.


 CREATE OR REPLACE TRIGGER derive_commission_pct  
 BEFORE INSERT OR UPDATE OF salary ON employees  
 FOR EACH ROW  
 WHEN (NEW.job_id = 'SA_REP')  
 BEGIN  
  IF INSERTING THEN  
   :NEW.commission_pct := 0;  
  ELSIF :OLD.commission_pct IS NULL THEN  
   :NEW.commission_pct := 0;  
  ELSE   
   :NEW.commission_pct := :OLD.commission_pct+0.05;  
  END IF;  
 END;  
 /  

Trigger'lardaki İşlem Sırası:

1-Önce "Before" triggerı varsa çalışır.
2-Sonra varsa "Before Row" triggerı kullanılır.
3-Ertesinde triggeri içerisinde yapılacak işlemler yapılır
4-"After Row" trigger'ı bulunuyorsa o çalıştırılır.
5-"After" triggerı tetiklenir.

Trigger'la ilgili Tablolar:


 user|all|dba_triggers



Örnekler:

1-
 CREATE TRIGGER rt BEFORE UPDATE OR DELETE OR INSERT ON sal   
 FOR EACH ROW BEGIN   
  stat.rowcnt := stat.rowcnt + 1;   
 END;   
 /   

Buradaki örneğimizde yarattığımız trigger, update,delete ve insert ifadelerinden sonra tablodaki her değer için bir değeri  bir arttırmaktadır.

2-
 CREATE TRIGGER at AFTER UPDATE OR DELETE OR INSERT ON sal   
 DECLARE   
  typ CHAR(8);   
  hour NUMBER;   
 BEGIN   
  IF updating   
  THEN typ := 'update'; END IF;   
  IF deleting THEN typ := 'delete'; END IF;   
  IF inserting THEN typ := 'insert'; END IF;   
    
  hour := TRUNC((SYSDATE - TRUNC(SYSDATE)) * 24);   
  UPDATE stat_tab   
   SET rowcnt = rowcnt + stat.rowcnt   
   WHERE utype = typ   
    AND uhour = hour;   
  IF SQL%ROWCOUNT = 0 THEN   
   INSERT INTO stat_tab VALUES (typ, stat.rowcnt, hour);   
  END IF;   
    
 EXCEPTION   
  WHEN dup_val_on_index THEN   
   UPDATE stat_tab   
    SET rowcnt = rowcnt + stat.rowcnt   
    WHERE utype = typ   
     AND uhour = hour;   
 END;   
 /

Buradaki örneğimizde de yine sütun belirtmeden tablomuza yapılan bir update,delete veya insert transaction'ınından sonra bir kere çalışmak üzere, her  trigger update için çalıştıysa bir kolon değeri update diye, diğer işlemler için de aynı şekilde çalışacak şekilde bir trigger yaratmaktayız. Bu örneğin genel amacı bir tabloya yapılan güncellemeleri loglamaktır.

3-


 CREATE OR REPLACE TRIGGER DBA.Trigger  
   BEFORE INSERT OR UPDATE  
   ON DBA.Logs  
   REFERENCING NEW AS NEW OLD AS OLD  
   FOR EACH ROW  
 DECLARE  
   TYPE session_type IS TABLE OF SYS.V_$SESSION%ROWTYPE;  
   
   session_tab  session_type;  
 BEGIN  
   IF (  UPPER (:NEW.UPDT_BY_OSUSER) ^= UPPER (:OLD.UPDT_BY_OSUSER)  
     OR UPPER (:NEW.UPDT_BY_MACHINE) ^= UPPER (:OLD.UPDT_BY_MACHINE))  
   THEN  
    RAISE_APPLICATION_ERROR (-20000, 'You Cannot Update UPDT_BY* columns!');  
   ELSE  
    SELECT s.*  
     BULK COLLECT INTO session_tab  
     FROM sys.v_$session s  
     WHERE s.audsid = USERENV ('SESSIONID') AND ROWNUM = 1;  
   
    :NEW.UPDT_BY_USER := SESSION_TAB (1).USERNAME;  
    :NEW.UPDT_BY_OSUSER := SESSION_TAB (1).OSUSER;  
    :NEW.UPDT_BY_MACHINE := SESSION_TAB (1).MACHINE;  
    :NEW.UPDT_TIMESTAMP := SYSDATE;  
   END IF;  
 END Trigger;  
 /  

Trigger'da var olan eski değerler ile tablonun içerisine aktarılacak yeni değerleri ayırt etmek için bir ifade bulunmaktadır.

"REFERENCING NEW AS NEW OLD AS OLD"

Bu kullanımla satırların hangi sütununa ekleme veya değişiklik yapılıyorsa :NEW veya :OLD şeklinde sütunun değişiklikten önceki ve sütunun değişiklikten sonraki hallerine referanslar yapılabilinir. Sütuna insert edilmeye çalışılan ve update edilmeye çalışılıan değer :NEW ile erişilebilinirken eski değere :OLD ile erişilebilinir. Bu procedure içerisinde eski değer yeni değerle karşılaştırılarak bir tutarsızlık varsa hata verdirilmektedir. Ertesinde de eğer hata çıkmaz ise kullanıcının girdiği değerler başka bir sütuna belirli değerlerle kaydedilir.

ORA-25001 Hatası:
ORA-25001 hatası view'lar üzerine trigger yaratmaya çalıştığımızda olmaktadır. Bu sorunun çözümü yaratılacak trigger'ı instead of ile trigger'ı ile değiştirmektir.




31 Aralık 2013 Salı

PL\SQL Örnekleri: SID ve Serial# Bulunması - Tek Satırlık Değerlerin Değişkenlere Atanması

Buradaki örneğimizde SID ve SERIAL# bulmaktayız.SID ve SERIAL#'ı dışarıdaki bir sorgudan çekmekteyiz. Sorgudan değerlerimizi çektikten, bunları scriptimiz içinde yazdırabiliriz.

COLUMN SID NEW_VALUE abc  
COLUMN SERIAL# NEW_VALUE efg  
   
 select SID ,SERIAL# from v$session where SID=1703;  
   
   
 declare  
 begin  
   
 dbms_output.put_line('SID = '||:abc||' SERIAL#= ' || :efg);  
 end;  
 / 

Tek satırlık değerleri değişkenlere atamak için "COLUMN" dedikten sonra sorguda değerini alacağımız kolon adını yazıp new_value dedikten sonra kullanacağamız değişkene atarız. Aşağıdaki yapıda oluşturmuş oluruz.

- COLUMN sütun_adı NEW_VALUE değişken_adı -

PL\SQL Örnekleri: Veritabanı Versiyonu Kontrolü Örneği - Global Parametreler

Buradaki örneğimizde değişken kullanımını inceleyeceğiz. Değişkenimizi yarattığımız scriptin üzerinde tanımlarız. Böylece genel olarak kullanabiliriz. Genelden kastımız ise bunun büyük bir kod olduğunu düşünseydik yani büyük bir paket olduğunu varsaysaydık  diğer fonksiyonlarımız içerisinde de :v_version değişkenini kullanmak için böyle bir yol uygulayabiliriz. V_version parametresinin yanındaki ":" işareti ile de parametrenin global olduğunu beliritiriz.

Aşağıdaki kodda v$instance'dan çektiğimiz versiyon değerini v_version adlı parametreye atarız. Sonra bu parametreyi uygun bir şekilde substr fonksiyonuyla ayırdıktan sonra bununla ilgili kontrol işlemlerimizi yaparız.

1.script

 variable        v_version               varchar2(17);  
 declare 
 BEGIN  
   
   select version  
   into :v_version  
   from v$instance;  
   
 :v_version := substr(:v_version,1,9);  
   
 if :v_version < '8.1.6.0.0'   
 and :v_version > '4.0' then  
 dbms_output.put_line(chr(10));  
 dbms_output.put_line('RDBMS Version = '||:v_version);  
 dbms_output.put_line('ERROR - Versiyon çok düşük');  
 dbms_output.put_line(chr(10));  
 end if;  
   
 exception  
   
  when others then  
   dbms_output.put_line(chr(10));  
   DBMS_OUTPUT.PUT_LINE('ERROR - RDBMS Versiyon hatası '|| sqlerrm);  
     
 END;  
 / 

Global özelliğini göstermek için aşağıdaki kodumuzu ya SQL*PLUS'tan ya da Toad'dan f5 tuşuna basaraktan çalıştırıp görebiliriz. Aşağıdaki kodumuzda ilk script'imizde atadığımız v_version parametremizi ikinci scriptimiz içinde de direk kullanabiliriz.

İlk script de atanan değer aynı session içerisinde 2. scriptde de kullanılabileceğini göstermek için aşağıdaki scripti çalıştırabiliriz.

2.script
 declare  
   
 BEGIN  
   
   select MAX(version)  
   into :v_version  
   from v$instance;  
   
 :v_version := substr(:v_version,1,9);  
   
 if :v_version < '8.1.6.0.0'   
 and :v_version > '4.0' then  
 dbms_output.put_line(chr(10));  
 dbms_output.put_line('RDBMS Version = '||:v_version);  
 dbms_output.put_line('ERROR - Versiyon çok düşük');  
 dbms_output.put_line(chr(10));  
 end if;  
   
 exception  
   
  when others then  
   dbms_output.put_line(chr(10));  
   DBMS_OUTPUT.PUT_LINE('ERROR - RDBMS Versiyon hatası '|| sqlerrm);  

 END;  
 /  
   
 declare  
 begin  
   
 dbms_output.put_line('RDBMS Version = '||:v_version);  
 end;  
 /  






19 Kasım 2013 Salı

PL\SQL Örnekleri: Authid Nedir? - Ne İşe Yarar?

Authid ifadesi veritabanına  programın, procedure ya da function'ın hangi kullanıcının haklarıyla çalıştırılması gerektiğini söyler. Invoker's rights yani programı çalıştıran kişinin mi yoksa programı yaratan kişinin haklarının kullanılması büyük fark yaratır.

Programımızı yaratan kişi kullanan kişiden daha üstün olabilir. Bu durumda programı çalıştıran kişi daha az object üzerinde hakka sahip olduğu için programın içinde kullanılmış olabilecek herhangi bir object kullanma yetkisi yoksa hata alacaktır. Bunu engellemek ya da düzenlemek için Authid ifadesini kullanırız.

Authid ifadesini kullanabilmek için "Authid" ifadesini başlıktaki "IS" veya "AS" anahtar sözcüklerinden önce kullanmak gerekmektedir.

Seçenekler:

Authid definer: default olarak kullanılmaktadır. Yani normalde programı oluşturan kullanıcının hakları ile çalıştırılır.

Authid current_user: Programımızı yaratan değil de, şu an çalıştıran kullanıcının haklarıyla çalıştırır.

Avantajı Nedir?

Object'lerin çalıştırılması sırasında bu şekilde ayırt edilmesi bize ayrı bir katman yaratır, güvenlik sağlar. Bu şekilde birden fazla aynı object'i kullanabilir. Kod paylaşılırken erişilebilen object'ler(data) ayrı tutulabilinir. İstediğimiz object'i paylaşmak istediğimizde bu yapıyı, programın içine atarak erişebiliriz.

Özetle; datalar ayrı ama kodlar paylaşılırken bu yapı kullanılabilir. Ancak bu sayede data başka birisinin tablespace'indeyken erişim sağlanabilir.


Syntax?

Syntax olarak daha önce de belirttiğimiz gibi procedure veya fonksiyonlarda isimden sonra kullanılacak şekilde konulur ve "AS" ve "IS" yapılarından önce konulur.

Örneğin aşağıdaki yapılarda DBA rolüne sahip birisi olarak aşağıdaki prosedürü yaratıp DBA rolüne sahip olmayan birinin kullanımına AUTHID DEFINER olarak verirsek procedure  çalışacaktır. Halbuki AUTHID CURRENT_USER olarak verilirse procedure çalışmayacaktır; çünkü kullanıcı DBA rolüne sahip olmayacaktır.


 CREATE OR REPLACE PROCEDURE definer_test AUTHID DEFINER IS   
 BEGIN  
  FOR rec IN (SELECT table_name FROM dba_tables)  
  LOOP  
   dbms_output.put_line(rec.table_name);  
  END LOOP;  
 END definer_test;  
 /  
   
 CREATE OR REPLACE PROCEDURE cu_test AUTHID CURRENT_USER IS   
 BEGIN  
  FOR rec IN (SELECT table_name FROM dba_tables)  
  LOOP  
   dbms_output.put_line(rec.table_name);  
  END LOOP;  
 END cu_test;  
 / 

18 Kasım 2013 Pazartesi

Oracle Veritabanı: PL\SQL Paketleri - PL\SQL Packages

Oracle PL\SQL Packages Nedir?

Package olarak bahsettiğimiz yapılar çeşitli PL\SQL tiplerinin, fonksiyonların, procedure'leriin ve alt programcıkların toplandığı object'lerdir..

Package'lar genelde 2 ayrı birimden oluşurular. Ilk birim "specification ya da spec" dediğimiz package içerisinde bulunan fonksiyon ve procedure'lerin başlık kısmının yazıldığı yerdir. Bu kısımda paket içerisinde yer alacak fonksiyonlar ve procedure'leri ifade ederiz. Bunu da başlık kısımlarını yani procedure veya fonksiyon diyip ismini yazıp yanına da alacağı parametreleri yazarak gerçekleştiririz.

 İkinci birim ise "body"'dir. "Body" içerisinde fonksiyon ve procedure'lerin kodları yer alır. Burada fonksiyon ve procedure'lerin nasıl gerçekleşeceğini yani kaynak kodlarını yazarız.
Package Yapısı

PL\SQL Package Örneği:

Bu örneğimizde bir PL\SQL package'ının nasıl yaratıldığını göstereceğiz. Bu işleme önce package spec'i ile başlarız. Yukarıdaki tanımımız da yaptığımız gibi ilk önce paketimizi içinde yer alacak fonksiyon ve prosedürler ile bunların alacağı parametreleri yazarak oluştururuz. Buradaki paketimizin adı deneme3'tür. Örnek olarak oluşturduğumu procedure'lar ise deneme ve deneme2'dir.


CREATE OR REPLACE PACKAGE deneme3 AS   
   PROCEDURE deneme(  
   yas number,  
   isim varchar2(10),  
   soyisim varchar2(10)  
 );  
   PROCEDURE deneme2(  
    sehir varchar2(20)  
 );  
 END deneme3;  

"deneme" ve "deneme2" olarak oluşturduğumuz iki procedure'de ise deneme ve deneme2 adlarıyla oluşturulmuş iki tabloya değerler girilir.

 CREATE OR REPLACE PACKAGE BODY deneme3 AS    
   PROCEDURE deneme(   
   yas number,   
   isim varchar2(10),   
   soyisim varchar2(10)   
     ) IS  
      BEGIN  
        insert into deneme values(yas,isim,soyisim);  
      END deneme;   
   
   PROCEDURE deneme2(   
   sehir varchar2(20)   
       )   
     BEGIN  
        insert into deneme2 values(sehir);  
      END deneme2; ;   
       
  END deneme3; 

Package'larımız içine procedure'lerimizi tanımladıktan sonra bu procedure'leri dışarıdan aşağıdaki gibi çağırabiliriz. Örneğin:

exec (schema_ismi).(package_ismi).(prosedür_ismi)(parametreler);  

Bu örneğimiz için uyarlarsak eğer;

exec berke.deneme3.deneme2('istanbul');  


PL\SQL Package'ları Oluşturmanın Amacı Nedir?

-Modülerlik:

Package'ların en temel özelliği procedure ve fonksiyon gbi yapıların gruplanmasına olanak sağlamaktadır. Böylece yapılan işe özel tasarlanmış fonksiyon ve prosedürler aynı yapı altında tutulabilinir.

-Fonksiyonellik ve Uygulama Tasarlama Kolaylığı:

Package'ların içine konan yapılar sayesinde uygulamamıza özel tasarladığımız package'lara ekstra fonksiyonlar ve tipler, cursor'lar tanımlayabiliriz. Bu şekilde hem bizim için uygulama dizaynında kolaylık sağlanır hem de package'ların eklenen programlarla etkeni genişler.

-Performans Artışı:

Performans artışı package çağırıldığı zaman hafızaya yüklenmesiyle oluşur. Bu şekilde uygulama sırasında package'ın diğer bütün  fonksiyonlarının veya prosedürlerinin kullanılmasıyla performans artışı sağlanır. Daha hızlı çalıştırılır.

-Gizlilik: 

Uygulamalar paketin sadece spec dediğimiz arayüzüne ulaşabilirler. Paketin içindeki kodları göremezler.

-Overloading: Birden Fazla Aynı Adlı Program

Overloading dediğimiz şey aslında java'da bulunan bir programlama tekniğidir. Program içerisinde yer alan fonksiyon veya prosedürler parametreleri değişik olduğu sürece,  veya parametreleri aynı olup da birinde fazladan parametre olduğunda paket derlenmesinde bir sorun yaşanmaz. Peki niye aynı adlı programlar yazdığımız konusuna geldiğimizde ise, paketimizin içindeki programların modülerliğinin veya fonksiyonalitesinin artması için bunu yapabiliriz.

Var Olan Paketlerin Text'lerini Nasıl Görebiliriz?


 select * from dba_source where name='STANDARD' and type ='PACKAGE BODY' order by line asc;

Yukarıdaki sorguyla paketlerin içlerini görebiliriz. Arayüz olarak bahsettiğimiz kısımlarını görmek içinse type'ı Package olarak değiştirebiliriz.


PL/SQL Paketlerinin Kalıcılığı:

Paketler çağrıldıkları andan itibaren yüklenirler. Değişkenler UGA kısmında yer alırlar. Yüklendikten itibaren session süresince UGA'de saklanırlar. Eğer "PRAGMA SERIALLY_REUSABLE" ifadesi kullanılırsa, programın sadece çağrıldığı süre boyunca memory'e yüklenir, sonra bu alan boşaltılır. Eğer memory bakımından kıstımız varsa ve session boyunca açık kalması gerekmiyorsa yararlı olur. Ayrıca işlerimiz geçici ise yine paketlerimizde pragma ifadesini kullanabiliriz.

"Pragma Serially_reusable" Spec örneği:

CREATE PACKAGE pkg1 IS
   PRAGMA SERIALLY_REUSABLE;
   num NUMBER := 0;
   PROCEDURE init_pkg_state(n NUMBER);
   PROCEDURE print_pkg_state;
END pkg1;
/

"Pragma Serially_reusable" Body örneği:

CREATE PACKAGE BODY pkg1 IS
   PRAGMA SERIALLY_REUSABLE;
   PROCEDURE init_pkg_state (n NUMBER) IS
   BEGIN
      pkg1.num := n;
   END;
   PROCEDURE print_pkg_state IS
   BEGIN
      DBMS_OUTPUT.PUT_LINE('Num: ' || pkg1.num);
   END;
END pkg1;
/


Hem Body hem de Spec tanımında Pragma serially_reusable ifadesi kullanılmaktadır. İkisinden birinde kullanılması yetmez.

Paketlerde PL/SQL Tablo Tipinde Kayıtların Kullanılması (Using PL/SQL Tables of Records in Packages):

PL/SQL tablo tipindeki kayıtların kullanılması demek paketler içerisinde belirtilecek tabloların içerisindeki sütunlar baz alınarak oluşturulacak tabloların geçici olarak sonuç depolaması demektir. Bu tanımı örneklerimizden de daha kolay bir şekilde görebiliriz. Bunun için ilk olarak paketimiz içerisinde bu tablo tipini tanımlamamız gerekir.

 CREATE OR REPLACE PACKAGE emp_pkg IS  
  TYPE emp_table_type IS TABLE OF employees%ROWTYPE INDEX BY BINARY INTEGER;  
  PROCEDURE get_employees(p_emps OUT emp_table_type);  
 END emp_pkg;  
   

Yukarıdaki örneğimizde de "employees" tablosunun bütün kolonlarını baz alan emp_table_type adında bir değişken tipi oluşturulur. Sonrasında bu tipte bir değişkeni geri döndürecek bir prosedür yazılır. Yani bu prosedürde get_employees içerisindeki işler çalıştırılır. Sonrasında bu işlere göre p_emps adlı değişken içine değerler atılır.

 CREATE OR REPLACE PACKAGE BODY emp_pkg IS  
  PROCEDURE get_employees(p_emps OUT emp_table_type) IS  
   v_i BINARY_INTEGER := 0;  
  BEGIN  
   FOR emp_record IN (SELECT * FROM employees)   
   LOOP  
    p_emps(v_i) := emp_record;  
    v_i:= v_i + 1;  
   END LOOP;  
  END get_employees;  
 END emp_pkg; 

Paketin yukarıda belirttiğimiz body kısmında get_employees adlı prosedürümüz içeriğini oluştururuz. "employees" adlı tablodan bütün veriler alınıp bunlar set edilecek.

Bu paketin kullanımına dair örneğimiz de aşağıdadır.

 DECLARE  
  v_employees emp_pkg.emp_table_type;  
 BEGIN  
  emp_pkg.get_employees(v_employees);  
  DBMS_OUTPUT.PUT_LINE('Emp 4: '||v_employees(4).last_name);  
 END;  

Örnekteki programda da paketimizin içinde tanımladığımız tablo tipinde bir değişken oluştururuz. sonra paketimizdeki get_employees prosedürünün içine atıp set ederiz. Yani tablomuzu içindeki değerlerle oluştururuz.  Oluşturduktan sonra da o tablonun istediğimiz index'li datasını çekebiliriz.


7 Kasım 2013 Perşembe

PL\SQL Örnekleri: Tablo Geri Döndürmek - Bir Fonksiyondan Tablo Nasıl Döndürülür?

Bir fonksiyondan tablo döndürmek için önce bu tablonun temsil edileceği bir "object" yaratmamız gerekir. Bunun için aşağıdaki syntax'ı kullanaraktan örneğimiz için bir tane yaratırız.

create type deneme is object (isim varchar2(10), soyisim varchar2(10));

Yukarıdaki nesneyle sürekli yaratacağımız tablonun yapısını oluştururuz.

Bundan sonra bu "object" ile çıkaracağımız tablo tipini oluştururuz.

 create type deneme_tab is table of deneme;  

Bu şekilde bir tablo tipi oluşturmuş oluruz. "deneme_tab" artık bizim için bir değişken tipi haline gelmiştir. Yani " abc deneme_tab" diyerekten deneme_tab biçiminde adı abc olan bir tablo oluşturmuş oluruz.

 create or replace function deneme_fonk return deneme_tab  
   is  
     abc deneme_tab := deneme_tab();  
     //deneme_tab tipinde bir tablo yaratırız.  
   
     n integer := 0;  
   begin  
     for a in (select isim,soyisim from musteriler)  
 //Buradaki cursor'da musteriler tablosundan isim ve soyisim  
 //bilgileri alınır  
     loop  
      abc.extend;  
      n := n + 1;  
     abc(n) := deneme(a.isim,a.soyisim);  
 //Burada ise abc'nin oluştuğu data tipinden bir kayıt  
 // atmaktayız.  
    end loop;  
    return abc;  
   end;  
   / 

Yukarıdaki kodumuzda deneme_fonk adlı deneme_tab tipinde bir tablo döndüren bir fonksiyon bulunmaktadır. Öncesinde daha önceden yarattığımız tablo yapısında bir tablo yarattıktan sonra musteriler adlı bilgileri içeren tablodan örnek kayıtları alıp buna göre  abc adlı deneme tablomuza ekletiriz.

select * from table (deneme_fonk);  

Yukarıdaki şekilde de tablomuzu fonksiyonumuzdan çekeriz.


8 Ekim 2013 Salı

PL\SQL Örnekleri

Burada bana gelen bazı isteklere göre pl\sql örnekleri koyacağım.

1- PL\SQL'de tabloya veri yazdırma:

Bu örneğim için ilk olarak bir deneme tablosu yarattım.

create table scott.deneme as select * from dual;  

Sonrasında hemen tablo içerisinde var olan bilgiyi  tabloya tekrar koyan bir pl\sql kodu yazdım.


 declare
 x varchar2(10);  
   
 begin  
   
 select * into x from dual;  
 dbms_output.put_line(x);   
 insert into scott.deneme values(x);  
 end;    

Burada bir değişken yaratıp o değişkene tablomuz içindeki tek değer olan dummy tablosundaki x değerini "X" parametresine atıp o "X" parametresini de tablomun içine attım.

Sonuçları görmek için "commit" lemeyi unutmayın. Gözden kaçabilir. Insert yaptığınız için hemen sonuçlar kaydedilmemektedir.


2- PL\SQL'de bir tablodan gelen her sonucu işleyip ona göre başka bir tabloya yazmak, girmek.
Aynı zamanda  "CURSOR FOR LOOP" örneği olarak da kullanılabilinir.

Önce geçen örnekte olduğu gib tekrar bir tablo yaratırız.

create table scott.deneme1 as select * from scott.emp;

Sonra procedure'umuz yazarız.

 declare  
   
 y SCOTT.EMP%ROWTYPE;  
  cursor z is select * from scott.emp;  
 begin  
   
 for a in z   
 loop  
   
 dbms_output.put_line(a.ename);   
 insert into scott.deneme1 values(a.empno,a.ename,a.job,a.mgr,a.hiredate,a.sal,a.comm,a.deptno);  
 end loop;  
   
 end; 

Buradaki örneğimizde bize bir tablodan hem bir sürü sayıda sonuç hem de birden fazla bilgi gelmektedir. Örneğin "select * from scott.emp" için aşağıdaki sonuçlar gelmektedir.

 7369     SMITH     CLERK     7902     12/17/1980     800          20  
 7499     ALLEN     SALESMAN     7698     2/20/1981     1600     300     30  
 7521     WARD     SALESMAN     7698     2/22/1981     1250     500     30  
 7566     JONES     MANAGER     7839     4/2/1981     2975          20  
 7654     MARTIN     SALESMAN     7698     9/28/1981     1250     1400     30  
 7698     BLAKE     MANAGER     7839     5/1/1981     2850          30  
 7782     CLARK     MANAGER     7839     6/9/1981     2450          10  
 7788     SCOTT     ANALYST     7566     12/9/1982     3000          20  
 7839     KING     PRESIDENT          11/17/1981     5000          10  
 7844     TURNER     SALESMAN     7698     9/8/1981     1500     0     30  
 7876     ADAMS     CLERK     7788     1/12/1983     1100          20  
 7900     JAMES     CLERK     7698     12/3/1981     950          30  
 7902     FORD     ANALYST     7566     12/3/1981     3000          20  
 7934     MILLER     CLERK     7782     1/23/1982     1300   

Bu kadar sayıda gelen sonucu ayrı ayrı işlemek için bir for loop'una ihtiyacımız vardır. Burada bunun için bir cursor, bir de kullanacağımız rowtype tipinde değişken yaratırız. Ondan sonra cursorımıza çekeceğimiz değerlerin sorgusunu veririz.  For loop'u içinde de aldığımız her değeri tekrar tablomuzu sokarız. Yani tablonunun içindeki verileri çoğaltmış oluruz. En son olarak commit'leyip "select count(*) from scott deneme1"  'den ne kadar kere verilerimizi çoğaltmış olduğumuzu görebiliriz.

3- Bu yazımızda da tablo geri döndürmenin PLSQL de nasil yapıldığını göstereceğiz.

16 Temmuz 2013 Salı

Veritabanındaki Prosedürler

Veritabanındaki prosedürleri bulmak için bakabileceğimiz birkaç tane  yer var. Bunlardan bir tanesi all_source'tur. all_source tablosunun kullanımına göre, user_source ve dba_source tablolarına da bakabiliriz. Bu tablolarda yazdığımız fonksiyon, prosedür, package gibi programların text'lerini, sahiplerini, isimlerini gibi bilgilerini edinebiliriz. Bu tablolarda tam olarak , fonksiyonların, paketlerin, triggerların, java kodlarının bilgileri bulunur.

İlk olarak prosedürümüzün varlığını kontrol etmek için dba_objects tablosuna bakabiliriz.

SELECT *
  FROM DBA_OBJECTS
 WHERE object_type = 'PROCEDURE' ;

Aynı şekilde dba_procedures tablosu da incelenebilinir.

SELECT *
  FROM DBA_PROCEDURES
 WHERE PROCEDURE_NAME = 'BERKE_DENEME';

Prosedürlerin parametrelerini görmek için ise desc sorgusunu kullanabiliriz.

DESC BERKE_DENEME;

Prosedürün text'ini görmek içinse all_source veya en yukarıda bellirttiğimiz gibi dba_source veya user_source tablolarına bakabiliriz.

SELECT text
FROM all_source
WHERE name = 'BERKE_DENEME'
and owner='BERKE'
ORDER BY line;

Prosedürleri compile etmek için aşağıdaki gibi bir syntax kullanırız.

 alter procedure prosedür_adı compile;  


15 Temmuz 2013 Pazartesi

Oracle E-Business Suite: ORACLE error 6550 in FDPSTP kodlu Concurrent Program Hatası

Aşağıda verdiğimiz hata, bir Concurrent programı Application içinde bir request olarak çalıştırdığımızda karşımıza çıkıyordu. Bu hatanın bir kaç tane nedeni olabilir.

ORACLE error 6550 in FDPSTP

Cause: FDPSTP failed due to ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'DENEME_BERKE2'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
.

Öncelikle yazdığımız prosedürle ilgili ayrıntılara dikkat etmeliyiz. Yani:

1- Eğer synonyms  kullandıysak bunun apps içinde yaratıldığına dikkat etmeliyiz.
2- Eğer başka bir şema adı altında bir obje ürettiysek, APPS kullanıcısının bunlara erişiminin olmadığını bilmeliyiz.
3- Yukarıda belirttiğimiz parametreler aynı zamanda "in" parametreleri değil de "out" parametreleri olmalılar.
4- Kullandığımız prosedürde errbuf veya retcode parametrelerinin kullanıldığından emin olmalıyız.



Errbuf ve retcode parametrelerinin kullanımına örnek olarak aşağıdaki prosedürü gösterebiliriz.

 CREATE OR REPLACE PROCEDURE deneme_berke2 (errbuf      OUT VARCHAR2,retcode     OUT VARCHAR2) is
    s_sql    VARCHAR2(500);
 BEGIN
 s_sql:='DROP TABLE XXIS_FA.deneme_berke purge';
 execute immediate s_sql;
INSERT INTO xxis_fa.xx_hello_world_tab VALUES (SYSDATE);

END;

Prosedürlerde ' DROP TABLE ' İfadesi



Prosedürlerde DDL ifadelerini kullanmak için dinamik sql yazmamaız gerekir. Eğer dinamik sql kullanmazsak programımız çalışmaz. Bunun için aşağıdaki gibi bir prosedür yazmamız gerekir. Bu örneğimizde kullanmak üzere aşağıdaki gibi bir tablo yaratacağız.

create table Apps.deneme_berke (creation_date date);

Tablomuzu oluşturduktan sonra aşağıdaki gibi bir prosedür yazar ve ifademizi test ederiz.

 CREATE OR REPLACE PROCEDURE deneme_berke1 IS
    ifade   VARCHAR2(500);
 BEGIN
 INSERT INTO apps.deneme_berke VALUES (SYSDATE);
 --İlk önce tablomuza günün tarihini atarız. Sonra da tabloyu sileriz.
ifade:='DROP TABLE XXIS_FA.deneme_berke purge';
 execute immediate ifade;

END;

13 Kasım 2012 Salı

PL/SQL Ders 13


Hata ve İstisna(Exception) Yönetimi
1   

Hata yönetimi nedir?
            PL/SQL çalışma sırasında gerçekleşecek hataların yönetimini kullanıcılara sağlar. Bunu da “Exception” hata yönetimi kısmında sağlar. Herhangi bir hatayla karşılaşılınca, bu hatanın içeriğiyle ilgili bir mesaj iletilir.

        Hata yönetim yapısı:
            
Genel hata yönetimi

DECLARE
   Tanım kısmı(Declaration section )
 BEGIN
   Hata tanım kısmı(Exception section )
 EXCEPTION
 WHEN excep1 THEN
    -ifadeler
 WHEN excep2 THEN
    -ifadeler
 WHEN Others THEN
   -ifadeler
END; 

PL/SQL Ders 12


Prosedür ve Fonksiyonlardaki Parametreler

Prosedür ve Fonksiyonlara nasıl parametreler aktarılır?

1)In tipindeki parametreler: Bu parametreler prosedürlere değer göndermek için kullanılırlar.

2)Out tipindeki parametreler:  Bu parametreler prosedürlerden değer almak için kullanılırlar. Bunların kullanımı fonksiyonlardaki döndürülecek değişkenlerin kullanımına benzer.

3)In Out parametreleri: Bu parametreler hem değer göndermek için hem de değer almak için kullanılırlar.

1        In parametresi:
CREATE [OR REPLACE] PROCEDURE prosedür_ismi (
 param1 IN veri_tipi, param2 IN veri_tipi )
In ifadesi aslında opsiyoneldir. Zaten otomatik olarak değişkenler aksi belirtilmediği sürece in tipindedirler.

2      Out parametresi:
            CREATE [OR REPLACE] PROCEDURE prosedür_ismi (param OUT veri_tipi)
            Burada parametrenin out olması özellikle önem taşır. Bu prosedürden farklı veriler gönderilcekse bunlar out olarak belirtilmelidir çünkü out otomatik olarak değişkenlere atanmazlar.

3       In Out  Parametresi:

            CREATE [OR REPLACE] PROCEDURE proc3 (param_name IN OUT datatype)

PL/SQL Ders 11


PL/SQL Fonksiyonları

PL/SQL fonksiyonu nedir?

            Fonksiyonlar prosedürlere benziyen PL/SQL bloklarıdır. Prosedürlerden en büyük farkları, fonksiyonların her zaman bir değer döndürmesi gerektiğidir. Buna karşılık prosedür de böyle bir gereklilik yoktur.

Genel yazım şekli:

CREATE [OR REPLACE] FUNCTION fonksiyon_ismi [parametreler]
RETURN dönülcek_veri_tipi; 
IS 
Tanım kısmı(Declaration_section )
BEGIN 
Çalıştırma kısmı(Execution_section )
Return dönülcek_değişken; 
EXCEPTION 
Hata tanımlama kısmı(exception section )
Return dönülcek_değişken; 
END;

Dönülcek_veri_tipi fonksiyonun başlangıcında ifade edilir. Bu tip herhangi bir Oracle tanımlı veri
 tipi olabilir: varchar,number gibi. Çalıştırma ve hata kısımlarının 2’si de bir değişken dönmelidirler.

1> CREATE OR REPLACE FUNCTION calisan_detay_fonk
2>    RETURN VARCHAR(20);
3> IS
5>    emp_name VARCHAR(20);
6> BEGIN
7>        SELECT first_name INTO emp_name
8>        FROM tablo WHERE empID = '100';
9>        RETURN emp_name;
10> END;
11> /

Bu örnekte çalışan id’si 100 olan çalışanın adını ekrana yazdırırız.

PL/SQL fonksiyonu nasıl çalıştırılır?
1)Fonksiyonlar birden fazla şekilde çalışıtırılabilinirler. Bütün fonksiyonlar bir değer döndürdük-
leri için direk olarak bir değişkene atanabilirler.
Calisan_ismi := calisan_detay_fonk;
2)Herhangi bir select ifadesinin bir parçası olarak:
Select calisan_detay_fonk from dual;
3)Bir PL/SQL ifadesi içinde:
Dbms_output.put_line(calisan_detay_fonk);