Blog ' da Ara

Loading

28 Temmuz 2011

PL/SQL COMPOSITE (KARMAŞIK) VERİ TİPLERİ

                                                               
                PL / Sql ile programlama yaparken veri kaynağı olarak tabloları kullanırız. Yaptığımız işler tablolardan verileri okuyup, bu verileri yorumlayarak yine tablolara veriler eklemek yada tabloları güncellemek olarak temel anlamda tanımlanabilir. Bu işlemleri yaparken diğer programlama dillerindeki gibi  kontrol blokları , döngüler, hata denetim sistemleri vs. kullanılır. Ancak bazen diziler ile işlemler yaptığımızda yada değişken olarak kullanmak istediğimiz veri bir tek veri değilde bir kolon yada bir row olursa, ya bu verileri değişkenlere parçalamamız yada karmaşık veri tiplerini kullanmamız gerekir.Bu yazımızda advanced derecede veri tipleri pl/sql de nelerdir, nasıl kullanılır açıklamalar ve örnekler yazacağız.
                PL / Sql karmaşık veri tiplerini iki gurupta incelemek mümkündür.
                PL/Sql Record :Bu veri tipi birbirleri arasında ilişki bulunan ancak tipleri benzemeyen verileri için kullnılır.Mesela bir ürünün adını, fiyatını, seri numarasını tutan bir record yazabiliriz.Bu ürüne ait bilgileri değişkenlerde tutmak istesek 3 adet değişken tip tanımlamamız gerekir. Ürün adı için varchar2, fiyatı için number ve seri numarası içinde number olacak şekilde. Ancak record ile tüm bilgileri tek bir değişkende tutabiliriz.
                PL/Sql Koleksiyon : Koleksiyonlar ise aynı tip ancak birden çok verileri turmak için idealdir. Mesela Tüm çalışanların isimlerini tek bir koleksiyon tutabiliriz.Koleksiyon tipleri,

·         Nested table
·         Index By Table
·         Varray  ' dir.
                Yani aklımızda kalması açısından, recordlar bütün bir row bilgisini, koleksiyonlar ise bütün bir kolon bilgisini tutabilir.Ne kadar veri tutabilir sorusuna gelince kısıtlama vardır. Bu veri tiplerini teker teker inceleyip örneklendirirken kapasite konusunda bilgi vereceğiz.
                PL /Sql RECORD
·         Herbir record birden çok farklı veri tipi için tanımlanabilir.
·         Reocrd lar başlangıç değerlerini tutabilir ve not null olarak tanımlanabilir.
·         Memory de tutulabilir, diske yazılmaya ihitiyaç duymazlar.
·         Recordlar nested tanımlanabilir. Yani bir record diğer bir recordun bileşeni olabilir
Record kullanabilmek için declare bölümünde bir record type tanımlanması gereklidir.
PL SQL Record


                                               
TYPE : Sizin tanımladığınız recordun tipidir.
type_name : Type adı.
field_name : record içine tanımlanacak alanların adı.
field_type : record içine tanımlanacak alanların data tipi.
identifier : record adı.
                Aşağıdaki örnek bir record nasıl tanımlanır ve kullanılır görebiliriz. Ancak dikkat edilmesi gereken , bir record en fazla bir row içerir, aksi takdirde "ORA-01422: tam okuma istenilenden daha fazla sayıda satır döndürür" hatasını alırsınız.
örnek 1 : Farklı tablolardan alınacak bazı değerler için record kullnımı.
DECLARE
   TYPE emp_info
   IS
      RECORD (
         DEPARTMENT_ID   NUMBER,
         EMPLOYEE_ID     NUMBER,
         FIRST_NAME      VARCHAR2 (32),
         LAST_NAME       VARCHAR2 (32),
         EMAIL           VARCHAR2 (32),
         HIRE_DATE       DATE
      );

   emp_kayit   emp_info;
BEGIN
   SELECT   d.department_id,
            e.employee_id,
            e.first_name,
            e.last_name,
            e.email,
            e.hire_date
     INTO   emp_kayit.department_id,
            emp_kayit.employee_id,
            emp_kayit.first_name,
            emp_kayit.last_name,
            emp_kayit.email,
            emp_kayit.hire_date
     FROM   hr.employees e, hr.departments d
    WHERE   E.DEPARTMENT_ID = D.DEPARTMENT_ID AND employee_id = 100;

   DBMS_OUTPUT.put_line (
      'our_emolyee department_id : ' || emp_kayit.department_id
   );
   DBMS_OUTPUT.put_line ('our_emolyee name : ' || emp_kayit.first_name);
   DBMS_OUTPUT.put_line ('our_emolyee hire_date : ' || emp_kayit.hire_date);
END;
Örnekteki pl/sql bloğu bize aşağıdaki çıktıyı verecektir.
                                our_emolyee department_id : 90
                                our_emolyee name : Steven
                                our_emolyee hire_date : 17/06/2003

                Eğer record birden çok tabloda değilde tek bir tablo üzerinde oluşturulacaksa %ROWTYPE kullanmak bizi record içeriğini tanımlamaktan ve ayrıca record içine veri atarken tek tek record fieldlerine yazmaktan kurtartabilir.Aşağıdaki örnek rowtype kullanımını gösterir niteliktedir.

örnek 2:  %rowtype kullanımı.
DECLARE
   emp_kayit   hr.employees%rowtype;
BEGIN
   SELECT   *
     INTO   emp_kayit
     FROM   hr.employees
    WHERE   employee_id = 100;

   DBMS_OUTPUT.put_line ('our_emolyee name : ' || emp_kayit.first_name);
   DBMS_OUTPUT.put_line ('our_emolyee last_name : ' || emp_kayit.last_name);
   DBMS_OUTPUT.put_line ('our_emolyee hire_date: ' || emp_kayit.hire_date);
END;

                Bu örneğin bize vereceği output ise aşağıdaki gibi olacaktır.
our_emolyee name : Steven
our_emolyee last_name : King
our_emolyee hire_date: 17/06/2003
                Recordlar kullanılarak tüm dml işlemleri yapılabilir. "insert into emp values emp_kayit;" . değişkenlerle yapılan tüm işlemler recordlar ilede yapılabilir. Recordlar C++ daki structure yapısnı anlatırlar. PL/Sql koleksiyonlarda array lere benzerler.

                PL/Sql KOLEKSIYON
Index by Table;
                Index by table koleksiyon tipini iki kolonu olan ve bu kolonlardan biri id değeri tutan ve primary key constraint içeren diğer kolon ise normal değer tutan kolona sahip bir tablo gibi düşünebiliriz.Birinci kolon index içeriğine sahiptir, ikinci kolon ise sclar yada record data tipine sahip olarak veriler tutabilir. Aşağıdaki resim de index by table yapsını daha net görebilirsiniz.

Index By Table Yapısı

                Index by table kullanırken exist, count, prior, next, delete parametrelerini kullanabiliriz, Aşağıda bu parametrelerin ve index by table kolleksiyon tipinin kullnımına yönelik örnekler bulabilirsiniz.
örnek 3 : bir tablonun tek bir kolonundaki bir kısım veriyi stoklayan index by table kullnımı .
DECLARE
   TYPE emp_name
   IS
      TABLE OF hr.employees.first_name%TYPE
         INDEX BY PLS_INTEGER;

   ename   emp_name;
BEGIN
   FOR i IN 100 .. 200
   LOOP
      SELECT   first_name
        INTO   ename (i)
        FROM   employees
       WHERE   employee_id = i;
   END LOOP;

   FOR i IN ename.FIRST .. ename.LAST
   LOOP
      DBMS_OUTPUT.put_line (ename (i));
   END LOOP;
END;
örnek 3 e ait output aşağıdaki gibi olacaktır.
Steven
Neena
Lex
Alexander
Bruce
David
......
örnek 4 : tüm tablonun kolonlarının index by table ile alınması

DECLARE
   TYPE emp_name
   IS
      TABLE OF hr.employees%ROWTYPE
         INDEX BY PLS_INTEGER;

   ename   emp_name;
BEGIN
   FOR i IN 100 .. 200
   LOOP
      SELECT   *
        INTO   ename (i)
        FROM   employees
       WHERE   employee_id = i;
   END LOOP;

   FOR i IN ename.FIRST .. ename.LAST
   LOOP
      DBMS_OUTPUT.put_line (
         'ad : ' || ename (i).first_name || ' soyad: ' || ename (i).last_name
      );
   END LOOP;
END;
örnek 4 e ait output aşağıdaki gibi olacaktır.
ad : Steven soyad: King
ad : Neena soyad: Kochhar
ad : Lex soyad: De Haan
ad : Alexander soyad: Hunold
ad : Bruce soyad: Ernst
......

Nested Table;
                Nested table da index by table fonksiyonelitesine benzerdir. Ancak mantık olarak farklılıklar vardır.Nested by table da data tipi belirli olmalıdır, index by table da belirli data tipine gerek yoktur.Nested tableda 1.kolon key tipi index by table daki gibi pls_integer değildir ve negatifde olamaz.Nested table da rowlar düzenli bir sırada değildir.Başlangıç noktası ilk değeridir.Ayrıca nested table lar index by table aksine database de depolanabilir.Nested table kavramı için aşağıdaki şekile göz atabiliriz.

Nested Table Yapısı

                                                
TYPE emp_type IS TABLE OF hr.employees.first_name%TYPE;
ename emp_type;
                Burada  ename tipinin değerini eğer belirlemezseniz nested table da null olarak belirlenir. Index by tableda ise boş olarak belirlenir.
ename tipine     ename := emp_type('scott','steve','king'); şeklinde değer atanabilir.
örnek 5 : nested table kullanımı;
DECLARE
   TYPE emp_type IS TABLE OF hr.employees.first_name%TYPE;
   ename   emp_type;
BEGIN
   ename := emp_type ('scott', 'steve', 'king');
   FOR i IN 1 .. ename.COUNT
   LOOP
      DBMS_OUTPUT.put_line (ename (i));
   END LOOP;
END;
örnek 5 bize aşağıdaki gibi bir output verecektir.
scott
steve
king
...
VARRAY :
                Varray tipi koleksiyonlar da nested table gibidir ancak varray için size tanımlamak gerekir.Ayrıca varray lerde nested table lar gibi en fazla 2 gb data tutabilir.Varray lerde database de depolanabilir.
TYPE emp_name IS VARRAY(2) OF hr.employees.first_name%TYPE;
ename emp_name;
Varray leryukarıdaki gibi tanımlanabilir.Mesela bizim tanımladığımız emp_name varray sadece 2 adet veri saklayabilir.3. veriyi girdiğinizde "ORA-06532: İndis sınırın dışında" hatasını alacaksınızdır.
örnek 6: Varray kullanımı
DECLARE
 TYPE emp_type IS VARRAY(3) OF hr.employees.first_name%TYPE;
ename emp_type;
BEGIN
   ename := emp_type ('scott', 'steve', 'king');

   FOR i IN 1 .. ename.COUNT
   LOOP
      DBMS_OUTPUT.put_line (ename (i));
   END LOOP;
END;
örnek 6 bize aşağıdaki gibi bir output verecektir.
scott
steve
king
                                ...
örnek 7 :Varray içine dinamik veri aktarımı ve bir prosedure input parametresi olarak array geçirilmesi.
Önce iki adet kolonu olan bir type oluşturalım. Şöyleki tipin bir kolonu id number, diğer kolonu ise name varchar2 olsun.
CREATE TYPE person AS object
            (id NUMBER(5), name VARCHAR2(30));
Daha sonra bu tipe bağlı olarak bir varray oluşturalım.
CREATE or replace  TYPE array_of_persons is varray(100) of person;
Bu aşamada artık varray veritababında saklanacak şekilde oluşturmuş olduk.Şimdi array_of_persons arrayını input olarak alacak prosedurumuzu yazalım.
CREATE OR REPLACE PROCEDURE write_person (p_array IN array_of_persons)
AS
BEGIN
   FOR i IN 1 .. p_array.COUNT
   LOOP
      DBMS_OUTPUT.put_line ('id -->'||p_array(i).id||' :name -->'||p_array(i).name);
   END LOOP;
END;
                Artık oluşturduğumuz varray tipini referans alarak bir değişken oluşturabilir bu değişkenin içinede istediğimiz tablounun id ve name kolonlarını atabiliriz. Yalnız dikkat edilmesi gerekn burada oluşturacağımız varray boyutu kadar değer atabilir ve sadece id iyi number ve name ide daha önce belirlediğimiz gibi varchar2  yapmalıyız.
                Aşağıdaki prosedurde ayrıca daha önce oluşturduğumuz write_person prosedurunude çağırarak output değerini alabiliriz.

DECLARE
   v_array   array_of_persons:= array_of_persons ();
   v_id number;
   v_name varchar2(30);
BEGIN
for i in 1..20 loop
select employee_id,first_name into v_id,v_name from hr.employees where employee_id=i+100;
   v_array.EXTEND;
   v_array (i) :=person(v_id,v_name);
   end loop;
  write_person (v_array);
END;
örnek 7 e aiti output aşağıdaki gibi olacaktır.

id -->101 :name -->Neena
id -->102 :name -->Lex
id -->103 :name -->Alexander
id -->104 :name -->Bruce
id -->105 :name -->David
id -->106 :name -->Valli
...

Bu makalemizde PL/Sql karmaşık veri tiplerini açıklamaya ve örneklendirmeye çalıştık.Faydalı olması dileğiyle..
Özcan YILDIRIM

1 yorum:

  1. Harika ama harika bir yazı olmuş. Özet halinde anlatmanızdan dolayı konuyu bilsem de zevkle okudum. Teşekkürler

    YanıtlaSil

"Sorularınız ve Eleştirileriniz Değerlidir"