11 Şubat 2011 Cuma

Oracle Hatalarını Output’a yazdırmak ve Loglamak




Merhaba arkadaşlar,
Bu makalede sık sık başımıza gelen bir konuya değineceğim. Oracle veritabanıyla çalışırken karşımıza cıkan ORA-… ile başlayan hatalar, yazdığımız prosedürün çalışmasını keser veya prosedürü dışarıdan bir arayüzden çağırıyorsak (.Net/JAVA/DELPHI v.s. ..) programın çakılmasına yol açar. Bu gibi durumlarda PLSQL bloklarımızın içinde, diğer dillerdeki Try-Catche mantığıyla çalışan “EXCEPTION” bloklarını yerleştireceğiz.
Oracle hatalarını yakalamak ve üzerinde işlem yapmak için (yazdırmak veya loglamak gibi…) “SQLERRM” parametresini kullanacağız. Basitçe aşağıdaki gibi bir örnekle açıklayalım :
DECLARE 
V_STRING VARCHAR2(3); 
BEGIN 
V_STRING := 'ERCAN';
DBMS_OUTPUT.PUT_LINE(V_STRING); 
END;
1
Görüldüğü gibi PLSQL bloğu çalışmadı ve hata verdi çünkü 3 karakterlik tanımladığımız varchar2 değişkene 5 karakterlik değer atadığımızdan dolayı ‘buffer too small’ hatasını aldık. Şimdi exception bloğu ekleyerek tekrar çalıştıralım :
DECLARE 
V_STRING VARCHAR2(3); 
BEGIN 
V_STRING := 'ERCAN'; 
DBMS_OUTPUT.PUT_LINE(V_STRING); 
EXCEPTION 
WHEN OTHERS THEN 
DBMS_OUTPUT.PUT_LINE(SQLERRM); 
END; 
PL/SQL procedure successfully completed.
2
Görüldüğü gibi exception bloğu sayesinde prosedür çalışıyor ve hatayı ekrana yazıyor.
Gelelim  hatayı loglamaya..
Aşağıdaki gibi bir table oluşturuyoruz.
CREATE TABLE ORA_LOG_TABLE( 
ORA_ERROR_CODE VARCHAR2(10), 
ORA_ERROR_MESSAGE VARCHAR2(100), 
ORA_USER VARCHAR2(12) DEFAULT USER, 
CUR_DATE DATE DEFAULT CURRENT_DATE 
); 
Table created.
Şimdi bloğumuzu aşağıdaki şekilde düzenliyoruz :
DECLARE 
V_STRING VARCHAR2(3); 
V_HATA_KOD VARCHAR2(10);
V_HATA_MESAJ VARCHAR2(100);
BEGIN
V_STRING := 'ercan';
DBMS_OUTPUT.PUT_LINE(V_STRING);
EXCEPTION
WHEN OTHERS THEN
V_HATA_KOD := SUBSTR(SQLERRM,1,9);
V_HATA_MESAJ := SUBSTR(SQLERRM,11,LENGTH(SQLERRM));
INSERT INTO ORA_LOG_TABLE(ORA_ERROR_CODE, ORA_ERROR_MESSAGE)
VALUES(
V_HATA_KOD,
V_HATA_MESAJ
);
COMMIT;
END;
PL/SQL procedure successfully completed.
SELECT * FROM ORA_LOG_TABLE;
3
Evet arkadaşlar, böylelikle ORA hatasını program çakılmasına sebep olmadan, yakaladık ve log’lamış olduk. Faydalı olmasını umarak iyi çalışmalar diliyorum.

ADD_MONTHS Fonksiyonu ve Gün Ekleme




SQL tarih fonksiyonlarından biri de add_months fonksiyonudur. Bu fonksiyonun çeşitli kullanım şekilleri vardır. Fakat fonksiyonun temel mantığı; girilen bir tarihten itibaren, verilen ay sayısı kadar geriye veya ileriye gitmektir. Fonksiyonu analiz edersek ;
add_months(‘date’,number)  şeklinde;
-date à girdiğimiz bir tarih,
-number à herhangi bir sayı (3,8,-4 gibi)
Şimdi fonksiyonu birkaç  örnekle inceleyelim :

İfade
Sonuç
1
ADD_MONTHS('10-APR-2010', 2)
10/06/2010
2
ADD_MONTHS(SYSDATE,2)
07/02/2011 14:00:15 --(çalıştırdığım tarih üzere)
3
ADD_MONTHS('15-JUL-1988',-2)
15/05/1988
4
ADD_MONTHS('31-JAN-2010', 1)
28/02/2010
5
ADD_MONTHS('30-JAN-2010', 1)
28/02/2010
6
ADD_MONTHS('29-JAN-2010', 1)
28/02/2010
7
ADD_MONTHS('28-JAN-2010', 1)
28/02/2010
8
ADD_MONTHS('27-JAN-2010', 1)
27/02/2010
9
ADD_MONTHS('30-JUN-1988',1)
31/07/1988
10
TO_DATE('31-JAN-2010') + 30
02/03/2010

Yukarıdaki tablonun her satırındaki örnekleri dikkatle incelemekte fayda var.
Tablodaki örneklerden ilkinde ; 10 nisan 2010 tarihine , 2 ay ekliyoruz ve sonuç olarak 10 haziran tarihine gidiyoruz. Aynı şekilde 3. Örnekte 15 temmuzdan 2 ay geriye giderek 15 mayıs tarihine geliyoruz fakat dikkat etmemiz gereken önemli bir nokta var : O da 4 ve sonraki satırlardaki örnekler.
4. Örnekte, 31 ocak tarihine bir ay eklediğimizde 28 Şubata gidiyor. Yani bu fonksiyon mantık olarak seçilen tarih üzerine 30 gün eklemiyor. Takvim üzerinde direk belirtilen günden “x ay sonrasına” gidiyor.   4,5,6 ve 7. Satırlardaki ifadelerin aynı sonucu döndürmesinin sebebi budur. 30 ocaktan 1 ay sonra da 28 şubattır; 28 ocaktan 1 ay sonra da 28 şubattır. Burada dikkat edilmesi gereken, ay ekleme işlemini gün bazında değil takvim bazında yapmasıdır.
10. örneğe baktığımızda ise ekleme işlemi tamamen gün bazında yapılmaktadır. Yani verilen tarihin üstüne takvim üzerinden x sayıda gün eklenir ve o sonuç döndürülür.



ORACLE – XML 2



XML verisini parse ederek  Oracle’da tabloya insert etme

Önceki yazımda  Oracle ‘da tablodan veriyi XML formunda çekmeyi anlatmıştım; bu yazımda ise aynı işlemin tersini yani XML formunda gelen bir stringin içinden veriyi parse ederek tabloya atma işlemini göstereceğim .
Daha anlaşılır olması açısından önceki tablomuzu kullanalım :
CREATE TABLE DBT
(
  NUM     NUMBER,
  ADI     VARCHAR2(14),
  SOYADI  VARCHAR2(22),
  TAR     DATE
);
Table created.
Şöyle bir xml imiz olsun :
<xml_formu>
       <NUM>1</NUM>
       <ADI>Ercan</ADI>
       <SOYADI>Yazgan</SOYADI>
       <TAR>2010-12-21</TAR>
</xml_formu>
Bu XML deki dataları tablomuza insert etmek için iki çeşit yol göstereceğim.
1) XML den her satırı ayrı ayrı parse edip insert yapmak.
DECLARE
 V_XML CLOB(500) := '<xml_formu>
                                                <NUM>1</NUM>
                                                <ADI>Ercan</ADI>
                                                 <SOYADI>Yazgan</SOYADI>
                                                 <TAR>2010-12-21</TAR>
                                        </xml_formu>';
BEGIN
    INSERT INTO DBT(NUM, ADI, SOYADI, TAR) VALUES(
                     XMLTYPE(V_XML).EXTRACT('/xml_formu/NUM/text()').GETNUMBERVAL(),
                     XMLTYPE(V_XML).EXTRACT('/xml_formu/ADI/text()').GETSTRINGVAL(),
                     XMLTYPE(V_XML).EXTRACT('/xml_formu/SOYADI/text()').GETSTRINGVAL(),
                     TO_DATE(XMLTYPE(V_XML).EXTRACT('/xml_formu/TAR/text()').GETSTRINGVAL())
                     );
                     COMMIT;
END;
PL/SQL procedure successfully completed.

Bu PL/SQL bloğunda , XML yapısının içindeki her datayı satır satır insert etme işlemi yapılıyor. Bu işlemi bir de şu şekilde yapabiliriz :
2) XML bloğunundaki datayı cursor’a taşıyarak cursor’dan okumak

DECLARE
 V_XML CLOB := '<xml_formu>
                             <NUM>1</NUM>
                             <ADI>Ercan</ADI>
                             <SOYADI>Yazgan</SOYADI>
                             <TAR>2010-12-21</TAR>
                              </xml_formu>';
CURSOR C1 IS
select extractvalue(column_value,'/xml_formu/NUM')         Numarasi,
         extractvalue(column_value,'/xml_formu/ADI')           Adi,
         extractvalue(column_value,'/xml_formu/SOYADI')     Soyadi,
         extractvalue(column_value,'/xml_formu/TAR')          Tarih
from table (xmlsequence(xmltype(V_XML).extract('/xml_formu')));
BEGIN
    FOR RW IN C1
    LOOP
        INSERT INTO DBT(NUM, ADI, SOYADI, TAR) VALUES(
        RW.NUMARASI,
        RW.ADI,
        RW.SOYADI,
        to_date(RW.TARIH)
        );
        COMMIT;
    END LOOP;
END;
PL/SQL procedure successfully completed.

Bu yol, çoklu veri alırken daha faydalı bir yoldur. Çünkü milyon satırlık bir xml kaydı geldiğinde o XML in içerisindeki milyon tane datayı ancak cursor vasıtasıyla loop kullanarak parse edersiniz, o yüzden  bu iki yolu da göstereyim dedim. “hah işte bunu arıyordum” demeniz dileğiyle J


Oracle XML -1


Oracle Table’lardan veriyi XML formunda çekme

CREATE TABLE DBT
(
  NUM     NUMBER,
  ADI     VARCHAR2(14),
  SOYADI  VARCHAR2(22),
  TAR     DATE
);
Şeklinde bir tablo oluşturalım.
Şimdi de tablomuza aşağıdaki kayıtları ekleyelim.
Insert into DBT
   (NUM, ADI, SOYADI,TAR)
 Values
   (1, 'Ercan', 'Yazgan', trunc(sysdate));
Insert into DBT
   (NUM, ADI, SOYADI)
 Values
   (2, 'yusuf', 'Arslan', trunc(sysdate));
Insert into DBT
   (NUM, ADI, SOYADI)
 Values
   (3, 'Samet', 'Aslan',trunc(sysdate));


Tabloya bir bakalım :)

select * from dbtable

Num     Ad         Soyad   Tar
-----      ------     -------   -------------
1          Ercan    Yazgan  21/12/2010
2          yusuf    Arslan   21/12/2010
3          Samet   Aslan    21/12/2010

Şimdi gelelim kuru fasulyenin faydalarına :) Biz bu var olan veriyi xml formunda görmek istiyoruz. Nerede kullanıldığına gelince; örnek olarak web service ile çalışan projelerde veriyi göndermek için xml formu kullanılır ve data transferi yapabilmek için datayı xml formuna sokmak gerekir. Bunun için biraz xml nedir gibi bir sorunun cevabını da vermek gerektiğini şu an hissettim :)

Xml bir veri taşıma formudur diyebiliriz. XML herhangi bir programlama dili veya bir script dil değildir.
Sadece, verinin platformlar arası anlaşılır, basit ve ortak bir görünümde taşınabilmesini sağlayan bir formdur. Mesela “Personel” adlı bi tablomuzda adı ve soyadı kolonları olsun. Hangi veritabanında tutarsak tutalım bilgisayar bu datanın aşağıdaki şekilde oldugunu anlamaz.

Personel

Adı       Soyadı
----       ---------
Ercan    Yazgan


Yani Veri formunu kendi kendine çözemez, adı : ercan soyadı : yazgan oldugunu sınıflayamaz. Fakat bu veri şu formda olduğu zaman tüm kaynaklar, veriyi anlayabilir ve sınıflayabilir :

<Personel>
            <adı>ercan</adı>
            <soyadı>yazgan</soyadı>
</Personel>

İşte bu xml formu görüldüğü gibi veriyi belli bir sınıf kapsamında hiyerarşiye sokuyor.

XML in ne oldugundan kısaca bahsettikten sonra lafı fazla uzatmadan konuya döneyim. Yukarıda oluşturduğumuz tablonun datasını xml formuyla çekmek için basitçe aşağıdaki kodu sorgulayabiliriz :

select xmlelement("xml_formu",
         xmlforest(d.NUM, d.ADI, d.SOYADI, d.TAR)
)
from dbtable d;

--Gelen sonuç :

<xml_formu>
<NUM>1</NUM>
<ADI>Ercan</ADI>
<SOYADI>Yazgan</SOYADI>
<TAR>2010-12-21</TAR>
</xml_formu>
<xml_formu>
<NUM>2</NUM>
<ADI>yusuf</ADI>
<SOYADI>Arslan</SOYADI>
<TAR>2010-12-21</TAR>
</xml_formu>
<xml_formu>
<NUM>3</NUM>
<ADI>Samet</ADI>
<SOYADI>Aslan</SOYADI>
<TAR>2010-12-21</TAR>
</xml_formu>

Burada bir konuya daha değinmek istiyorum, xmlelement herbir satırı bir element olarak görmek için kullanılır yani hersatırı başlıklamak gibi düşünebiliriz. Yoksa şu şekilde de bir sorgu yazabiliriz :

select   xmlforest(d.NUM, d.ADI, d.SOYADI, d.TAR)
from dbtable d;

--sonuç :

<NUM>1</NUM>
<ADI>Ercan</ADI>
<SOYADI>Yazgan</SOYADI>
<TAR>2010-12-21</TAR>
<NUM>2</NUM>
<ADI>yusuf</ADI>
<SOYADI>Arslan</SOYADI>
<TAR>2010-12-21</TAR>
<NUM>3</NUM>
<ADI>Samet</ADI>
<SOYADI>Aslan</SOYADI>
<TAR>2010-12-21</TAR>

Şeklinde gelecektir.

Umarım faydalı olmuştur, bir sonraki yazımda ise xml formundaki bir stringin içerisinden veriyi parse edip tabloya aktarmakla ilgili bir bilgi paylaşıyor olacağım.