26 Temmuz 2008 Cumartesi

SQL, PL/SQL, and Java

Veritabanı ile içli dışlı olan birisiyseniz mutlaka SQL i duymuşsunuzdur.Sanırım,veritabanı sorgulama ve yönetim dillerinden birisi kendisi..Hem de neredeyse bütün ilişkisel veritabanı sistemleri ile iletişim kurabilme yeteneği sayesinde çok özel bir yere de sahip bir vatandaştır.

SQL komutları iki alt grupta incelenir:

1-DDL - Data definition Language (Veri tanımlama dili)
2-DML - Data manipulation Language (Veri İşleme dili)

Verilerimizi işleyen komutlar SELECT,INSERT,UPDATE ve DELETE'tir.Bunlara aynı zamanda DML komutları da denir.

Select, istediğimiz tablodan kendi belirlediğimiz kriterlere göre kayıtları önümüze serer.Tabloda hangi alanları görüntülemek istiyorsak alan isimlerinin arasına virgül koymamız yeterlidir.Örnek vereyim:

SELECT isim,soyisim FROM ogrenci;

Beni bu kesmez,tablonun hepsini görmem lazım diyorsanız * karekterini çok seven birisi olmalısınız :) Niye mi,örneği inceleyin ;)

SELECT * FROM ogrenci;

Ama çoğu zaman böyle bütün bilgilerin çarşaf gibi gelmesini istemeyiz.Çünkü zaman kısa ve kısa zamanda en uygun bilgiye ulaşmamız gerçeği ile karşı karşıyayız ;) Tamam, merak etmeyin bunun da yolu var... Anahtar kelime ise WHERE

Diyelim ki, John Fred adlı müşterim faturasını ödediği konusunda beni ikna etmeye çalışıyor.Sonuçta bende John'un çetelesini tutan birisi değilim,ama sonuçta bu tezi çürütmek için antitez sunmak gerekiyor.İşte bu noktada veritabanım ve SQL yardımıma koşuyor.Diyorum ki:

SELECT * FROM SuleymanHolding where isim="John" and soyisim="Fred";

Yukarıdaki kurtarıcı meleğim sayesinde John'a dersini vermiş oluyorum böylece.Nasıl yöntem ama :P

Aslında WHERE i biraz daha tanıyalım diyorum ben,çünkü kendisine haksızlık olacak:

Where, genelde grup çalışmasını seven bir arkadaşımızdır.Sizi birlikte çalıştığı operatörlerle tanıştırayım isterseniz:

<> Büyük
>= Büyük veya eşit
<= Küçük veya eşit !<> Büyük değil
= Eşit
<> veya != veya # Eşit değil

Onlar da sizinle tanıştıklarına memnun olmuşlar :)

Az daha unutuyordum, AND, OR ve NOT ile de araları çok iyi.Birden fazla sorgu olduğunda bir araya geliyorlar.Yoksa birbirlerini aradıkları sordukları yok bana kalırsa.
SELECT * FROM ogrenci where cinsiyet="K" AND sinif=6 OR ogrencisayisi <60;

SQL, düzenli ve tertipli insanları düşünerek kendisine DESC ve ASC gibi iki önemli komutu eklemiştir. Bunlar da nedir diyebilirsiniz,biraz sabredin bende tam onu açıklayacaktım.DESC,verilerin azalan sırada,ASC ile verilerin artan sırada listelenmesini sağlar.Hem de istersen istediğimiz kriterlere göre bile verilerimizi artarak ya da azaltarak listeletebiliyoruz.

SELECT * FROM ogrenci ORDER BY tarih DESC;
(Tarih kriterine göre azalan bir sırada listeleyecektir.)

ASC, örneğini de siz düşünün,her şeyi devletten beklemeyin canım :P

Biliyorsunuz ki veritabanı içindeki tablolar ve alanlar birbiriyle çok sıkı fıkı olabiliyor.Bu nedenle bazı veriler birden fazla yerde geçebiliyor, ki bu da select arkadaşımızdan bazı alanları listelemesini rica ettiğimizde o bilginin birden fazla listelenmesine sebep oluyor.SQL, buna da çözüm bulmuş.Dedi ki, eğer bunu önlemek istiyorsan DISTICT komutu kullan:
SELECT DISTICT bolum FROM ogrenci where ogrenciid>20 ;

Tamam her şey hoş güzel de bana, 20 ile 30 arasındaki ogrenciler lazim,20 den büyük deyince 20 sonraki bütün öğrenciler listeleniyor.Ne anladım ben bu işten diyorsunuz değil mi :) SQL de çözümler biter mi hiç, sizi bugün bir de BETWEEN kardeşimizle tanıştırayım.Mesleği mi nedir? Tam sizin istediğiniz şeyi yapan işte bu eleman.Örneğin:

SELECT * FROM ogrenci where ogretmenmaas BETWEEN 600000 AND 900000;

Ama kriteriniz bir tarih ise şunu kullanmanızı öneriyorum,ama tercih sizin :P
SELECT * FROM ogrenci WHERE derstarihi BETWEEN {2100-06-01} AND {2999-02-03};

Hayatınızda bir günde bu kadar kişiyle tanıştığınız mı bilmiyorum ama son olarak sizi AVG,SUM,MIN,MAX ve COUNT isimli arkadaşlarla tanıştırmak istiyorum."Kendini lafla değil,işle ve eserle anlat" demiş ya bir düşünür,isterseniz bende bu arkadaşları size işle anlatayım :)

SELECT MIN(ogrenciid) FROM ogrenci WHERE sinif=6;

* 6. sınıftaki ogrenciid si en büyük olanı getirir.
SELECT MAX(ogrenciid) FROM ogrenci WHERE sinif=7;

*Evet mikrofon sizde ;)
SELECT SUM(ogrencisayisi) FROM ogrenci where bolum="sayisal";

* Sayısal bölümdeki bütün öğrencilerin toplam sayısını getirir.

SELECT AVG(yas) FROM ogrenci WHERE bolum="esitagirlik";

*Eşit ağırlıktaki öğrencilerin yaş ortalamasını getirecektir.

SELECT COUNT(*) FROM ogrenci;

*ogrenci tablosundaki kayıt sayısını görüntüler.

Şimdilik bu kadar, SQL yeter sanırım,sonra devam ederiz.Biraz da PL/SQL nedir,ne işe yarar ,ne eder ne yapar onu bir inceleyelim diyorum ben.

PL/SQL , SQL'in bir üst kümesi olmak üzere yordamsal olarak geliştirilmiş bir dildir.Özellikle bir defada çok fazla işlem yapmamız gerekiyorsa tek veritabanı bağlantısıyla işi bitirmemizi ve de veritabanı olaylarının tetiklenmesinde işimize oldukça yarar.

PL/SQL, tanımlanan bloglar ile veritabanının kapısını çalar.Yoksa veritabanı ile bir türlü anlaşamaz,çünkü veritabanı ondan düzenli,net tanımlı,kendinin anladığı bir dilden konuşmasını ister.PL/SQL 'de Anonymous,Procedure ve Function olmak üzere 3 blok türünde veritabanı ile sohbeti oldukça ilerletmiştir :)

Örnek vermek gerekirse:

Anonymous

[DECLARE]

BEGIN
--Deyimler
[EXCEPTION]
END;

Procedure

PROCEDURE name
IS

BEGIN
--Deyimler
[EXCEPTION]
END;

Function

FUNCTION name
RETURN datatype
IS

BEGIN
--Deyimler
RETURN value;
[EXCEPTION]
END;


Değişkenler bizim istediklerimizi yapan ve bizden iş isteyen sadık elemanlarımızdır.Ancak bazı şartları varmış,sizinle bu şartların en önemlilerini sizinle paylaşayım.Diyorlar ki:

*Beni tanımlarken bir harfle başlamalısın.

*Declerative kesiminde tanımlamalısın.

İsterseniz artık yavaş yavaş ilk PL/SQL bloğumuzu yazmaya başlayalım:

SET SERVEROUTPUT ON

--Açıklama Satırı

DECLARE

tk_ISIM VARCHAR(20);

BEGIN

select ISIM into tk_ISIM from OKUL where OKUL_SN=5;

DBMS_OUTPUT.PUT_LINE(‘5 nolu okulun adı:’ || tk_ISIM);

END;

Değişkenlerle çok sık haşir neşir olacağımız için bu elemanların özelliklerinden biraz daha bahsetmek istiyorum:

*Kendilerinin anlamlı adlarla çağırılmalarından çok hoşlanırlar.

*NOT NULL kısıtlaması varsa mutlaka ilk değerin atanmasını isterler.

*CONSTANT tanımlanıp da ilk değeri atamazsanız sizi yarı yolda bırakır.

*Siz siz olun,kolon adlarını değişken adı olarak kullanmayın ;)

%TYPE Kullanımı

%TYPE , ikide bir karşıma çıkıyor,bu da neyin nesidir diyebilirsiniz.Çünkü ben ilk gördüğümde öyle demiştim J Meğer ki, tanımladığımız değişken türünü mevcut veritabanındaki tablodan üretilmesini sağlıyormuş.

Kullanımı : değişken tabloadı.kolonadı%TYPE;

emp_lname employees.last_name%TYPE;

min_balance balance%TYPE=1000;

%TYPE i daha kalıcı olarak anlayabilmemiz için bir örnek üzerinde görelim isterseniz:

/* Bugünün ve yarının tarihini ekrana yazdırır.*/

SET SERVEROUTPUT ON

DECLARE

bugun DATE:=SYSDATE;

yarin today%TYPE; /* Burda birinci değişkenden %TYPE ile faydalandık. */

BEGIN
yarin:=bugun+1;

DBMS_OUTPUT.PUT_LINE(‘Hello World’);

DBMS_OUTPUT.PUT_LINE(‘Bugun:’ || bugun);

DBMS_OUTPUT.PUT_LINE(‘Yarın:’ || yarin );

END;

PL/SQL ‘i biraz daha yakından incelediğimde IF,WHILE,FOR gibi döngülere sahip olarak kendisinde güçlü bir yetenek katmış olduğunu gördüm.Tabi durur muyum,hemen bu yetenekleri nasıl kullanabilirim üzerinde araştırma yapmaya başladım…

İsterseniz biraz örneklere göz atalım:

IF KULLANIMI

DECLARE

not number:=31; /* İlk değer vermemiz önemlidir.Aksi takdirde ELSE kesimi işleyecektir.*/

BEGIN

IF not <11

THEN

DBMS_OUTPUT.PUT_LINE(‘Tembel bir ogrenciyim..’);

ELSEIF not<71

THEN

DBMS_OUTPUT_LINE(‘Orta duzey bir ogrenciyim’);

ELSEIF not<86

THEN

DBMS_OUTPUT_LINE(‘Basarili bir ogrenciyim…’);

ELSE

DBMS_OUTPUT_LINE(‘Henuz bilmiyorum,kendimi ariyorum :P’);

END IF;

END;

WHILE KULLANIMI:

DECLARE

ulkeid mevki.ulke_id%TYPE := ‘CA’;

mev_id mevki.mevki_id%TYPE;
yeni_sehir mevki.sehir%TYPE := ‘İzmir’;

sayac SAYI :=1;

BEGIN

SELECT MAX(mevki_id) INTO mev_id FROM mevki

WHERE ulke_id=ulkeid;

WHILE sayac <= 3 LOOP

INSERT INTO mevki(mevki_id,sehir,ulke_id) VALUES(mevki_id+sayac),yeni_sehir,ulkeid);

counter := counter+1;

END LOOP;

END;

FOR KULLANIMI:

DECLARE

Ulkeid mevki.ulke_id%TYPE :=’CA’;

mev_id mevki.mevki_id%TYPE;

yeni_sehir mevki.sehir%TYPE := ‘Hakkari’;

BEGIN

SELECT MAX(mevki_id) INTO mev_id

FROM mevki

WHERE ulke_id=ulkeid;

FOR i IN 1..3 LOOP

INSERT INTO mevki(mevki_id,sehir,ulke_id)

VALUES((mev_id+i),yeni_sehir,ulkeid);

END LOOP;

END;

Hep var olan tablolar üzerinden işlem yapıyoruz, hiç kullanıcıdan bilgi istemeyecek miyiz diye aklınıza soru gelebilir. Evet kesinlikle çok haklısınız. Onun için de ‘&’ i kullanıyoruz.

Örneğin;

UNDEFINE ISIM

SET SERVEROUTPUT ON

SET VERIFY ON

BEGIN

DBMS_OUTPUT.PUT_LINE(‘Adınız: &&ISIM’);

DBMS_OUTOUT.PUT_LINE(‘Adınız:’ || UPPER(‘&ISIM’));
END;

Sıra geldi, bileşik veri türlerine… Bu arkadaşları iki temelde inceleyebiliriz:

1-Satır temelli bileşik veri (PL/SQL Records) : Programlamadaki struct a benzetebiliriz.Tablonun bir satırının işlenmesi amaçlı değişkene aktarılması gerektiği durumlarda kullanılır.

Örneğin;

TYPE pers_record_type IS RECORD

(soyadi VARCHAR(25),

is_id VARCHAR(10),

maas NUMBER(8,2) );

pers_record pers_record_type;

pers_record.soyadi :=’Yıldırım’;

%TYPE’ nin akrabası olan %ROWTYPE ile tanışmaya geldi sıra… %ROWTYPE, bir tablonun satır yapısının aynısında PL/SQL Record değişkeni oluşturulmasını sağlar.Bu yapı derleme zamanı oluşturulur.Yani tablonun değişmesi durumunda kodun yeniden derlenmesi tavsiye edilir.

Örneğin;

DEFINE personel_no = 124

DECLARE

pers_rec emekli_personel%ROWTYPE;

BEGIN

SELECT personel_id,soyisim,is_id,yonetici_id,kira_tarihi,maas,komisyon,departman_id

INTO pers_rec FROM personel

WHERE personel_id = &personel_no;

INSERT INTO emekli_personel VALUES pers_rec;

END;

SELECT * FROM emekli_personel;

2-Birden çok veri saklayan bileşik veri (Index By Tables): Bu yapıyı iki kolonlu bir tablo gibi düşünebiliriz.Birinci kolon primary key gibi çalışırken,ikinci kolon değerleri saklamak için kullanılır.

Örneğin;

DECLARE

TYPE isim_tablo_tipi IS TABLE OF

personel.soyisim%TYPE

INDEX BY PLS_INTEGER;

TYPE kiratarihi_tablo_tipi IS TABLE OF

DATE

INDEX BY PLS_INTEGER;

tablo_ismi isim_tablo_tipi;

kiratarihi_tablo kiratarihi_tablo_tipi;

BEGIN

tablo_ismi(1) :=’ MODA’;

kiratarihi_tablo(2) := SYSDATE + 7;

IF tablo_ismi.EXISTS(1) THEN

INSERT INTO ….

….
END;

PL/SQL Record u farklı kullanım alanlarına bir göz atalım isterseniz:

Nested Table : Index By yapısı gibi dizelere benzer.Ayrıldıkları noktalar:

-Dizini negatif değerler almaz.

-Dizin değeri sıralıdır.

-Veritabanında VARCHAR2 gibi saklanabilir.

Örneğin;

SET SERVEROUTPUT ON

DECLARE

TYPE location_type IS TABLE OF locations.city%TYPE;

Offices location_type;

Table_count NUMBER;

BEGIN

Offices := location_type(‘Şırnak’,’Ağrı’,’İzmir’,’Ankara’);

table_count := offices.count();


FOR i in 1..table_count LOOP

DBMS_OUTPUT.PUT_LINE(offices(i));

END LOOP;
END;

Varray: PL/SQL’in farklı kullanımlarından bir tanesi de Varray’dir.En önemli özelliği dizi boyunun sabit olması ve dizi boyunun tanımlanırken belirlenmiş olmasıdır.

Belki daha bitmedi mi kardeşim,roman mı yazıyorsun diyebilirsiniz ama az kaldı biraz daha sabredin J

Explicit Cursor (Belirtilmiş İmleç): Bu garip şey de nedir diyor insan ilk gördüğünde değil mi? Şu işe yarıyormuş: Diyelim ki bir sorguyu çalıştırdık ve önümüze satırlar çıktı,bu çıkan satırlar geçici bir alanda saklanıyorlarmış.İşte explicit cursor tam bu noktada sahneye çıkarak o saklanan alanlardaki satırları çağırmamızı sağlıyorlarmış.

Örneğin;

SET SERVEROUTPUT ON
DECLARE

CURSOR emp_cursor IS

SELECT employee_id,last_name FROM employees

WHERE departman_id=30;

Empno employees.employee_id%TYPE;

Lname employees.last_name%TYPE;

BEGIN

OPEN emp_cursor;

LOOP

FETCH emp_cursor INTO empno,lname;

EXIT WHEN emp cursor%NOTFOUND;

DBMS_OUTPUT.PUT_LINE( empno || ‘’ || lname );

END LOOP;

CLOSE emp_cursor;

END;

SQL Cursor: Bazı zamanlarda kullanıcı tarafından açıkça cursor istenmemiş olabilir.Bu durumlarda Oracle sorgu sonucunda ilerleyebilmek adına kapalı bir SQL cursor kullanır.Bazı SQL Cursorlarından örnek vermek gerekirse: SQL%FOUND , SQL%NOTFOUND, SQL%ROWCOUNT diyebiliriz.

Örneğin:

VARIABLE rows_deleted VARCHAR2(30)

DECLARE

Empno employees.employee_id%TYPE := 176;

BEGIN

DELETE FROM employees

WHERE employee_id=empno;

:rows_deleted := (SQL%ROWCOUNT || ‘row deleted. ’);
END;

Stored Procedures & Functions : İlk başta blokları 3 e ayırmıştık.İsterseniz biraz da kısaca bu kalan bu iki blok hakkında biraz konuşalım.Daha iyi anlaşılması için anaonymous bloklarla stored Procedures & Functionları karşılaştıralım diyorum ben:

Anonymous Bloklar ; İsimsizdirler.Her çalışmada derlenirler.Veritabanında saklanmazlar.Başka bir uygulamaca çağrılmazlar.Değer döndürmezler.Parametre alamazlar.

Stored Procedures & Functionlar ise tam bunların tersini yapabildikleri için doğru yerde ve doğru zamanda kullanıldığında inanılmaz işimize yararlar.

Örneğin;

CREATE OR REPLACE FUNCTION check_ss1(empno employees.emplooyee_id%TYPE)

RETURN Boolean IS

dept_id employees.departman_id%TYPE;

sal employees.salary%TYPE;

avg_sal employees.salary%TYPE;

BEGIN

SELECT salary,department_id INTO sal,dept_id FROM employees WHERE employee_id=empno;

SELECT avg(salary) INTO avg_sal FROM employees WHERE departmen_id=dept_id;

ID sal > avg_sal THEN

RETURN TRUE;

ELSE

RETURN FALSE;
END IF;

EXCEPTION

WHEN NO_DATA_FOUND THEN

RETURN NULL;

END;

İşlev Çağırma:

BEGIN

DBMS_OUTPUT.PUT_LINE(‘Checking for employee with id 205’);

IF(check_sal(205) IS NULL ) THEN

DBMS_OUTPUT.PUT_LINE(‘Returned NULL due to exception’);

ELSEIF(check_sal(205)) THEN

DBMS_OUTPUT.PUT_LINE(‘Salary >average’);

ELSE

DBMS_OUTPUT.PUT_LINE(‘Salary

END IF;


END;

Amacımız PL/SQL’e kısa bir giriş yapmak olduğu için Trigger’lara da değinip bu yazımı sonlandırmak istiyorum:

Tetikleyici (Trigger) : Tetikleyiciler,olaylar yoluyla çalışırlar.Bir olaydan hemen sonra ya da hemen sonra çalışacak şekilde ayarlanabilirler.

Örneğin;

CREATE OR REPLACE trigger “t_SEQ_SEKTOR_PK” before insert

on “SEKTOR” for each row

BEGIN

SELECT “SEQ_SEKTOR_PK”.nextval

INTO : new.”SEKTOR_PK” FROM dual,

END;

Sözlerime burada son verirken son olarak oracle de java kullanımından birazcık bahsetmek istiyorum:

Oracle prosedürleri içerisinde bildiğiniz gibi Java kodu kullanmak mümkündür.Oracle, kendi içerisinde gömülü bir JVM içerir ve bu sayede istediğimiz Java kodunu Oracle veritabanı üzerinde tanımlayabilir ve çalıştırabiliriz.

Diyelim ki aşağıdaki gibi bir java kodumuz olsun:

create or replace and compile java source named runcommandjava as
import java.io.*;
import java.util.*;
public class RunCommandJava{
public static void run(String cmdText)
throws IOException, InterruptedException
{
int rtn;
Runtime rt = Runtime.getRuntime();
Process prcs = rt.exec(cmdText);
rtn = prcs.waitFor();
}
}

Bu java kodunu çalıştıracak Java prosedürünü şu şekilde yazabiliriz:

CREATE OR REPLACE PROCEDURE RUNOSCOMMAND
(param IN VARCHAR2) AS LANGUAGE JAVA
NAME 'RunCommandJava.run(java.lang.String)';

Çalıştırmak için de tek yapmamız gereken: exec runoscommand('echo deneme'); demektir.

Umarım faydalı bir yazı olmuştur.Lütfen varsa eksiklikleri ve düzeltmeleri paylaşınız.

2 yorum:

Tonguç dedi ki...

Süleyman emeğine sağlık, güzel bir giriş yazısı olmuş.

Adsız dedi ki...

Eline sağlık güzel olmuş.Size bir kaç soru soracağım cevaplarsanız memnun olurum.Benim projem var konu veri ambarı.Bu konu hakkında uygulama yapıp sunum yapmam gerekiyor.Veri ambarı için oracle kullanmak zorunlumu acaba?