Friday, July 31, 2009

ORACLE'DA INACTIVE SESSIONLARI KILL ETMEK

--bu işlemleri yapabilmeniz için ALTER SYSTEM yetkisine sahip olmanız gerekiyor.
DECLARE

  v_dyn_sql  VARCHAR2(500);

BEGIN

  v_dyn_sql := 'SELECT ''kill session ''|| s.SID || '','' || s.serial# || '' '' || '' immediate ;'' '

               ||' FROM v$session s, v$process p'

               ||' WHERE s.paddr = p.addr '

               ||' AND s.username IS NOT NULL '

               ||' AND s.username = ''bilgisayarimin makina adi'' '

               ||' AND s.osuser = ''isletim sistemimin adi'' '

               ||' AND s.last_call_et / 3600 > 1 '

               ||' AND s.status = ''INACTIVE'' '

               ||'ORDER BY logon_time';

  

  dbms_output.Put_line(v_dyn_sql);

  

  EXECUTE IMMEDIATE (v_dyn_sql);

END;



--UNIX üzerinden ORACLE'nin inactive session'larını kill etmek için aşağıdaki yönetemi uygulayabiliriz.
--UNIX'te çalışan bir işi kill etmek için gerekli olan script
--kill -9 "çalışan işin id'si"
--bu script'i üretmek için aşağıdaki select cümleciğini hazırlayalım.

set echo off
head off
veri off
pages 50000 lines 120
spool on oracle_kill_session.sh


SELECT   'kill -9 '

         ||p.spid

         ||' # '

         ||s.username

         ||' '

         ||s.program

FROM     v$session s,

         v$process p

WHERE    s.paddr = p.addr

         AND s.username IS NOT NULL

         AND s.username = 'bilgisayarimin makina adi'

         AND s.osuser = 'isletim sistemimin adi'

         AND s.last_call_et / 3600 > 1          --son bir saattir sistemde olanlar

         AND s.status = 'INACTIVE'                     --inactive duruma düsenler.

ORDER BY logon_time;

/

spool off


--şimdi kill scriptimizi hazırladık. Sıra bunu çalıştırmaya geldi.

--önce çalıştırabilir hale getiriyoruz oracle_kill_session.sh dosyasına execute edilebilme yetkisi verelim.
chmod 700 oracle_kill_session.sh
--burada 777 diyerek herez'e yetki vermek doğru olmayabilir. Buna dikkat edelim.
./oracle_kill_session.sh
--diyerek inactive sessionları kill ediyoruz.


--çok daha farklı kıstaslara göre kırılım yapabilirsiniz.
--bu kıstaslar aşaıdakililer olabilir.

--SID
--SERIAL#
--USER#
--USERNAME
--STATUS
--SERVER
--SCHEMA#
-- SCHEMANAME
-- OSUSER
-- PROCESS
-- MACHINE
-- TERMINAL
-- PROGRAM
-- TYPE
--PLSQL_OBJECT_ID
--MODULE
--LOGON_TIME
--LAST_CALL_ET

Monday, July 27, 2009

EN COK KAYNAK TÜKETEN SORGUYU BULMAK

EN COK KAYNAK TÜKETEN SORGUYU BULMAK
-- en cok kaynak tüketen sorguyu bulmak için aşağıdaki sorguyu kullanabiliriz.
--bu sorgu disk kullanımını bize göstermektedir.
--önce denemeler yapmak için hazırlık yapalım.

--bir tablo yaratalım. bu tabloya insert işlemi yaparak diski ne kadar yoruğunu göreceğiz.
create table kaynak_tuketim_deneme as select * from all_objects


--şimdi tablomuza sürekli olarak kayıt ekleyelim.
DECLARE

BEGIN

  FOR i IN 1.. 10 LOOP

    INSERT INTO kaynak_tuketim_deneme

    SELECT *

    FROM   all_objects;

    

    COMMIT;

  END LOOP;

END;


--çalışan sorgumuzu görmek için

SELECT /*+ ORDERED */ v.osuser,

                      v.schemaname,

                      Substr(Rpad(s.sql_text,64),1,64) sqltxt

FROM     v$session v,

         v$sqltext_with_newlines s

WHERE --v.osuser = 'aates'

 s.address = v.sql_address

         AND s.hash_value = v.sql_hash_value

ORDER BY piece


--ne kadar kaynak kullandığını hangi sorgunun ne kadar yet tükettiğini görmek için

SELECT *

FROM   (SELECT   Substr(a.sql_text,1,50)                                 sql_text,

                 Trunc(a.disk_reads / Decode(a.executions,0,1,

                                                          a.executions)) reads_per_execution,

                 a.buffer_gets,

                 a.disk_reads,

                 a.executions,

                 a.sorts,

                 a.address

        FROM     v$sqlarea a

        ORDER BY 2 DESC)

-- Burada ne kadar?n? listelemek istedi?imizi belirtiyoruz.

WHERE ROWNUM <= 10;



-- son olarak arkamızda pislik bırakmayalım.
drop table kaynak_tuketim_deneme

ORACLE HATALARINI YAKALAMA

-- Veritabani'mizdaki sorgular çalisirken alinan hatalari asagidaki sorgu ile tespit edebiliriz.

-- Warning: compiled but with compilation errors bu uyariyi aldigimizda

-- show errors ile alinan hataliri görebiliriz. Ama asagida anlatmaya çalistigimda ayni isi yapacaktir.

-- Öncelik ile kendimize bir senaryo hazirlayalim. Senaryomuz su sekilde olsun.

-- bir paket yazdik ve içerisinde çesitli tablolar join islemi yapiyor temp tablolar olusturuyor.

-- Bir çesit ETL paketi diyebiliriz. Bu paket çesitli tablolardan select yapiyor yada içerisinde dinamik SQL'ler var

-- Kod dynamik sql e girdigi zaman hata aldi ve siz bu hatalari listelemek yada görmek istiyorsunuz.

-- Bu raporu hazirlamak için iki adet oracle View'ini joinlemek yeterli olacaktir.

-- öncelik ile all_source'den (USER_SOURCE,DBA_SOURCE de olur yetkinize göre artik.) hata alan kodu aliyoruz.

-- bunu daha sonra error'lerin USER_ERRORS (DBA_ERRORS,USER_ERRORS)oldugu görünüm ile joinliyoruz.

SELECT a.owner,

       a.TYPE,

       To_char(a.line)

       ||' - '

       ||a.text

       ||' - '

       ||b.text error

FROM     dba_source a,

         user_errors b

--çalisan isi burada belirtiyoruz.

--hangi isin hata aldigini bilmiyorsak bu kisimi açiklamaya çevirebiliriz.

WHERE a.NAME = 'AA'

         AND a.owner = b.owner

         AND a.NAME = b.NAME

         AND a.TYPE = b.TYPE

         AND a.line = b.line

ORDER BY a.NAME,

         a.line;

--bu isin aynisini show erros ile de yapabilirsiniz. Derleme isinden sonra hatalari bize gösterecektir.

--ÖRNEK BIR UYGULAMAYI HEMEN YAPALIM.

--hatali çalisacak bir procedure hazirlayalim.

SET SERVEROUTPUT ON;


CREATE OR REPLACE PROCEDURE Aa

IS

--burada degiskenimizi açiklama satiri yaptik. bu sebepten dolayi

--PLS-00201: identifier 'v_dynsql' must be declared

--degisken tanimlanmalidir. hatasini alacagiz.

--v_dynsql varchar2(200);

BEGIN

  v_dynsql := 'bu bir ekran ciktisidir.';

  

  dbms_output.Put_line(v_dynsql);

END;
SELECT   a.owner,

         a.TYPE,

         To_char(a.line)

         ||' - '

         ||a.text

         ||' - '

         ||b.text error

FROM     dba_source a,

         dba_errors b

WHERE    a.NAME = 'AA'

         AND a.owner = b.owner

         AND a.NAME = b.NAME

         AND a.TYPE = b.TYPE

         AND a.line = b.line

ORDER BY a.NAME,

         a.line;

--yukaridaki sorgu ile hatayi ve alinan hatanin geçtigi kod'u görenibiliriz.

--kodumuz düzeltip tekrar çalistirdigimizda

SET SERVEROUTPUT ON;


CREATE OR REPLACE PROCEDURE Aa

IS

  v_dynsql  VARCHAR2(200);

BEGIN

  v_dynsql := 'bu bir ekran ciktisidir.';

  

  dbms_output.Put_line(v_dynsql);

END;

--bu kez hatasiz derlenecegi için herhangibi bir hata almayacaktir.

--sorgu sonucuda null dönecektir.

Thursday, July 23, 2009

PARTITION BAZLI KAYIT EKLEME

DECLARE

  dyn_sql       VARCHAR2(2000);

   -- KAYNAK TABLONUN BULUNDUGU SCHEMA

   v_owner  VARCHAR2(30) := 'HR';

   -- kaynak tablonun adi.

   v_table  VARCHAR2(30) := 'BU_TABLODAN';

   --partitionun tasinacagi (eklemenin yapilacigi partitionun oldugu) schema adi

   v_dest_owner  VARCHAR2(30) := 'SCOTT';

   --insert yapilacak olan tablonun adi.

   v_dest_table  VARCHAR2(30) := 'BU_TABLOYA';

BEGIN

  --database'deki butun partitionlar bizim tablomuza ait olan partitionlarin isimlerini çekiyoruz.

  --burada her iki partition isimlerinin de ayni oldugu varsayiliyor.

  --partition isimlerinin farkli oldugu durumlarda kodda düzenlemeye gitmek gerekebilir.

  --all_tab_partitions da HIGH_VALUE üzerinde i?lem yap?labilir.

  --high_value long b?r alan oldu?u için dönü?türme yapmak gerebilir.

  FOR i IN (SELECT partition_name

            FROM   all_tab_partitions

            WHERE  table_owner = v_owner

                   AND table_name = v_table)

  LOOP

    dyn_sql := ' INSERT /*+ append */ INTO '

               ||v_dest_owner

               ||'.'

               ||v_dest_table

               ||' PARTITION ('

               ||i.partition_name

               ||')
SELECT /*+ parallel (aa,16) */ *
FROM '


               ||v_owner

               ||'.'

               ||v_table

               ||' partition ('

               ||i.partition_name

               ||') aa ';

    

    dbms_output.Put_line(dyn_sql);

    

    --EXECUTE IMMEDIATE dyn_sql;

    COMMIT;

  END LOOP;

END;

UNIX'TE DOSYA PARÇALAMA

/home/aliates$ split -l 65000 bolunecek.csv bolunen_

Oracle'den spool ile aldığımız yada şöyle diyelim bir şekilde tabloyu text (csv) dosyaya aktardık. Bunu excell ile açmak istiyoruz. excell 2003'de 65000 (int kadar) satır destekliyor. ee napacaz bizim dosyada var 230.000 satır. İşte yukarıdaki komut bize verilen dosyayı istenilen satır sayısında parçalıyor.

GRANT EXECUTE YETKİSİ

--kendi semamizda proceduremizi olusturalim ve içerisinde yine kendi semamizdaki bir tabloyu silelim.

--tablomuzu yaratalim.

CREATE TABLE deneme_silsene (

  a NUMBER);


--procedure yaratalim

CREATE OR REPLACE PROCEDURE Deneme_sil

AS

  v_dyn_sql  VARCHAR2(200) DEFAULT NULL;

BEGIN

  v_dyn_sql := 'drop table deneme_silsene';

  

  EXECUTE IMMEDIATE v_dyn_sql;

  

  COMMIT;

END;

/


--baska bir semadan (userdan "hedefowner") baglanarak olusturdugumuz procedureyi çalistiralim.

BEGIN

  hedefowner.deneme_sil;

  

  COMMIT;

END;

/


--yetkiniz yok hatasi alacagiz bu hatayi asmak için yetki verelim.

--bu yetkiyi kendi semamiza baglanarak kendi schemamiz altinda vermemiz gerkiyor.

GRANT EXECUTE ON deneme_sil TO hedefowner;


-- procedure normal bir sekilde çalisti ve kendi tablomuzu sildi.

-- burada tablomuz için diger user'a yetki vermedik ama yine de tablomuz üzerinde islem yapabildi.

-- grant execute yetkisi sikintili bir yetki oldugunu buradan anlayabiliriz.

--söyle bir deneme de yapalim isterseniz.

--simdi procedureyi çalistiracagimiz schemada da ayni isimde bir tablo yaratalim ve hangi tabloyu silecegine bakalim.

-- bu konu hakkinda fikri olmayan arkadaslariniz ile iddaya girerek ögle yemegi kazanabilirsiniz.

--simdi su sekilde oldu son durum.

SELECT *

FROM   hedefowner.deneme_sil;


SELECT *

FROM   buradansiliyom.deneme_sil;


--iki farkli schemada ayni isimde tablom var

BEGIN

  hedefowner.deneme_sil;

  

  COMMIT;

END;

/


-- burada bu procedure'yi çagirir isem hangi tabloyu silecek. procedure schema adini belirtmedim. procedurenin yaratildigi yerdeki tabloyu mu silecek

-- yoksa calistirdigimiz yerdeki tabloyu mu silecek?

--iste bu sorunun cevabi procedurenin oldugu create edildigi schemadaki tabloyu silecektir.

--bu durumu asmak için yada kafa karistirmasina , olurda yanlis schema altinda islemler yapmasini engellemek için

--"schema_adi"."tablo_adi" seklinde çalismakta fayda var. bunu aliskanlik edinmek lazim.

DROP PROCEDURE hedefowner.deneme_sil;

Sunday, July 19, 2009

SEQUENCE KULLANIMI

Önce yetkilerinden bahsedelim.
sequence yaratmak ve bunlar üzerinde çeşitli işlemler yapabilmek için aşağıdaki yetkilerin olması gerekmektir.
--kendi schemanda oluşturmak için
create sequence
--bütün schemalarda oluşturmak için
create any sequence
--bütün schemalarda değiştirmek için için
alter any sequence
--bütün schemalarda silme yetkisine sahip olmak için
drop any sequence
--DB üzerindeki butun sequencelere erişebilmek için
select any sequence

--en basit sequence yaratma komutu aşağıdadir.

CREATE SEQUENCE seq_deneme;

SELECT seq_deneme.NEXTVAL FROM dual;

--bu komutun default değerler ile yaptığı aslında

CREATE SEQUENCE DENEME_TS.seq_deneme
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
CACHE 20
NOORDER;
--burada da görüldüğü gibi başlangıç değeri 1 bitiş değeri bir yıgın 9
--cycle şeklinde değildir. VS vs..

--denemelerde kullanmak için bir tablo yaratalım.
create table tablom as select object_id,object_name from all_objects where rownum<5;

--yatattığımız bir tabloya kayıt ekleyelim.
insert into tablom values (seq_deneme.nextval,'deneme_1')

commit;


--sequencenin şu anki değerini öğrenmek için aşağıdaki sordu işinjizi görecektir.
select seq_deneme.currval from dual;

--sequence değerini bir attıralim
select seq_deneme.nextval from dual;

--şimdi yeni değerine bakalim.
select seq_deneme.currval from dual;


--belirli bir değerden sequence başlatmak için aşağıdaki komut işimizi görecektir.

CREATE SEQUENCE seq_deneme_v1 START WITH 123;

select seq_deneme_v1.currval from dual;

-- ilk başta bunu kullanırsak aşağıdaki hatayı alırız.
-- ORA-08002: sira SEQ_DENEME_V1.CURRVAL henüz bu oturumda tanimlanmadi
-- bu hatadan kurtulmak için sequenceyi bir defa çalıştırmak gerekiyor.

select seq_deneme_v1.nextval from dual;

--bir sequence'i silmek için
drop sequence seq_deneme_v1 --komutunu kullanınız.



SELECT DBMS_METADATA.get_ddl ('SEQUENCE', 'DEN_SEQ') from dual;

--SQLPLUS ile sequencenin create script tam olarak görünmediği durumlarda
--aşağıdaki kod bloğu kullanılabilinir.
DECLARE
c_lob CLOB;
BEGIN
SELECT DBMS_METADATA.get_ddl ('SEQUENCE', 'DEN_SEQ')
INTO c_lob
FROM DUAL;
DBMS_OUTPUT.put_line (c_lob);
END;

ALTERNATİF SEQUENCE KULLANIMI

EĞER CREATE SEQUENCE Yetkiniz yok ise ve artan bir alan kullanmak zorunluluğunuz var ise aşağıdaki yöntemi kullanarak kendize bir sequence yaratabilirsiniz. Bu yöntem büyük databaselerde yada büyük tablolarda kullanmak mantıklı değildir. Max değeri bulmak sizde ciddi performans kaybına sebeb olacaktır.

--sequence kullanmaktan kaçmanın bir yöntemide budur diyebiliriz.
--tablomuzu yaratalım.
create table tablom as select * from all_objects where rownum<50;

--en buyuk değeri bularak değerini select cumleciğinde bir arttırıp değişkene atıyoruz.
--sonrada yeni değerimizde bu değişkeni kullanıyoruz.
DECLARE
en_buyuk_deger NUMBER;
BEGIN
SELECT MAX (object_id) + 1
INTO en_buyuk_deger
FROM tablom;
INSERT INTO tablom
(object_id,object_name
)
VALUES (en_buyuk_deger,'ali'
);
commit;
END;

Friday, July 17, 2009

SPLIT PARTITION KULLANIMI

Split partition büyük boydaki partition'u küçük parçalara ayırmaya yarıyor. partitionda belirli bir koşula göre alt parçalara ayırıyoruz. bu işlemi yaptıktan sonra tabloyu analiz etmede fayda var. Oracle'yi olandan bitenden haebrdar etmek lazım. :))

split partition ile ilgili bir çok örnek mevcud. bir tanesini de burada paylaşmak gerekir ise

--2008 yılının partitionlarını iki parçaya bölüyorum.
--TO_DATE('31-JUL-2009 23:59:59', 'DD-MON-YYYY HH24:MI:SS') haziran ayından öncekileri haziran dahil
-- buyuk_tablom_2008_01 partitionuna ekliyorum. Diğerlerinide buyuk_tablom_2008_02 partitionuna ekliyoruz.

ALTER TABLE buyuk_tablom
SPLIT PARTITION buyuk_tablom_2008 AT (TO_DATE('31-JUL-2009 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION buyuk_tablom_2008_01,
PARTITION buyuk_tablom_2008)
UPDATE GLOBAL INDEXES;

ALTER TABLE buyuk_tablom
SPLIT PARTITION buyuk_tablom_2008 AT (TO_DATE('31-DEC-2009 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
INTO (PARTITION buyuk_tablom_2008_02,
PARTITION buyuk_tablom_2008)
UPDATE GLOBAL INDEXES;



--eklenen partitionları burada görebiliriz.
SELECT partition_name, num_rows
FROM user_tab_partitions
WHERE table_name = 'BUYUK_TABLOM';
--istatistiğini alalım.

EXEC DBMS_STATS.gather_table_stats(USER, 'buyuk_tablom', cascade => TRUE);

crontab da logların mail olarak gelmesini engelleme

crontab'da çalışan sorguların sonuçlarını loglamak için bazen bir dizin girmemiz gerekir, bazende hiçbirşey girilmediğinde bunları mail olarak alırız. Bazen program sürekli log üretir ve yer sıkıntısı yapar ise logların gelmesini istemeyebilriiz. Bunun için log yerine sunu diyebiliriz.

log_ureten_script.sh >/dev/null

bunu yazarsak log üretmeyecektir.

UNIX'TE BACKUP ALMA

UNIX üzerinde backup alma ile ilgili küçük bir shell script yazdım. yaptığı sadece diskler üzerinde gezdirme yapıyor. en son silme işlemini yapıyor. Linux cu arkadaşlar cok beğenmebilir ama basit ve sade bir shell script oldu.


#!/usr/bin/bash
datetime=`date '+%y%m%d'`
source_location_1=/d101/data/original_files
source_location_2=/d102/backup/original_files
target_location_1=/d102/backup/original_files/folder_$datetime
target_location_2=/d103/backup/original_files/folder_yedek
old_file_move=`ls -rt /d102/backup/original_files/ |grep "folder"| head -1`
old_file_delete=`ls -rt /d103/backup/original_files/folder_yedek/ |grep "folder"| head -1`
size1=75
size2=63
#gelen LOG dosyalarını koyacağı klasor yok ise yaratılıyor.
if [ -d ${target_location_1} ]
then
echo "Hedef Dizin Mevcut ${target_location_1} "
else
mkdir ${target_location_1}
echo "Hedef Dizin Olusturuldu ${target_location_1} "
fi
#////////////////////////////////////////////////////////////////////////
#sıkıştırma işlemi yapılarak yer kazancı sağlanıyor
#burada zipleme işlemi yapılıyor.
echo "dosyalar zipleniyor."
for zipfile in ` ls ${source_location_1} | grep ".LOG$"`
do
gzip $zipfile
echo $zipfile
done
#////////////////////////////////////////////////////////////////////////
#zipli dosyaları bul ve aktar.
#zipli dosyaları oluşturdak sonra bunları ilgili gün için yaratılmış olan dizine taşır.
echo "d102 dizininde ilgili yere taşınıyor"
for tarih in `ls ${source_location_1} |grep ".LOG.gz$"| awk '{print substr($1,4,6)}'`
do
file_pattern="???$tarih*.LOG"
mv ${source_location_1}/${file_pattern}.gz ${source_location_2}/folder_${tarih}/
echo ${source_location_1}/${file_pattern}.gz ${source_location_2}/folder_${tarih}/
done
#////////////////////////////////////////////////////////////////////////
#d102 nin %60 i doldugunda d103 e aktar.
#en eski dosyayı taşıyor.
echo "d102 dizininden d103 dizinine taşınıyor"
while [ $size1 -lt `df | grep /d102 | cut -c 38,39` ];
do
mv ${source_location_2}/${old_file_move} ${target_location_2}
echo ${source_location_2}/${old_file_move} ${target_location_2}
done
#////////////////////////////////////////////////////////////////////////
#d103 %70 doldugunda en eski olanı siliyor.
echo "d103 dizininden siliniyor."
while [ $size2 -lt `df | grep /d103 | cut -c 38,39` ];
do
rm -R ${target_location_2}/${old_file_delete}
echo ${target_location_2}/${old_file_delete}
done
echo "işlemler bitti"

SİLİNEN VE OLUŞTURULAN NESNELERİ LİSTELEME

--TABLOLARıMıZı YARATALıM.

--karşilaştırma yapmak için aşağıdaki tabloyu kullanıyoruz.

CREATE TABLE OBJECT_TAKIP
(
OWNER VARCHAR2(30 BYTE),
OBJECT_ID NUMBER,
OBJECT_NAME VARCHAR2(128 BYTE),
OBJECT_TYPE VARCHAR2(19 BYTE)
)


--silinen yada oluşturulan nesneler de burada

CREATE TABLE CRE_OR_DEL_OBJECT
(
OWNER VARCHAR2(30 BYTE),
OBJECT_ID NUMBER,
OBJECT_NAME VARCHAR2(128 BYTE),
OBJECT_TYPE VARCHAR2(19 BYTE),
STATUS VARCHAR2(10 BYTE)
)



CREATE OR REPLACE PROCEDURE object_takip_proc
IS
v_dynsql VARCHAR2 (1000);
v_owner VARCHAR2 (150);
BEGIN
v_owner := '''HR''';
-- Mail ile gönderecegimiz verileri tabloya aktariyorum. Silinenler ve olusturulanlar bu tabloda tutuluyor.
v_dynsql := 'TRUNCATE TABLE CRE_OR_DEL_OBJECT';

EXECUTE IMMEDIATE v_dynsql;

--SILINEN OBJELER
--OBJECT_TAKIP tablosu doldurulduktan sonra silinen objeleri yakaliyor.
v_dynsql :=
'INSERT INTO CRE_OR_DEL_OBJECT
(OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS)
SELECT o.owner, o.object_name, o.object_type, ''SILINDI''
FROM object_takip o LEFT OUTER JOIN all_objects a
ON o.object_type = a.object_type
AND o.object_name = a.object_name
WHERE a.object_name IS NULL
AND o.owner IN (''HR'', ''SCOOT'')
AND o.object_type IN ( ''TABLE'',''PROCEDURE'',''FUNCTION'',''PACKAGE'',''VIEW'')';

-- DBMS_OUTPUT.PUT_LINE (V_DYNSQL);
EXECUTE IMMEDIATE v_dynsql;

--OBJECT_TAKIP tablosu doldurulduktan sonra yeni yaratilan objeleri yakaliyor.
v_dynsql :=
'INSERT INTO CRE_OR_DEL_OBJECT
(OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS)
SELECT A.OWNER, A.OBJECT_NAME, A.OBJECT_TYPE, ''OLUSTU''
FROM ALL_OBJECTS A LEFT OUTER JOIN OBJECT_TAKIP O
ON O.OBJECT_TYPE = A.OBJECT_TYPE
AND O.OBJECT_NAME = A.OBJECT_NAME
WHERE O.OBJECT_NAME IS NULL
AND a.owner IN (''HR'', ''SCOOT'')
AND a.object_type IN (''PROCEDURE'', ''PACKAGE'', ''TABLE'', ''VIEW'',''FUNCTION'')';

--YENI YARATILAN TABLOALRI ASAGIDAKI SQL ILE DE BULABILIRIZ.
/* SELECT a.owner, a.object_name, a.object_type, ''OLUSTU''
FROM all_objects a
WHERE a.owner IN (''HR'', ''SCOOT'')
AND a.object_type IN (''TABLE'', ''PROCEDURE'', ''FUNCTION'', ''PACKAGE'')
MINUS
SELECT o.owner, o.object_name, o.object_type, ''OLUSTU''
FROM object_takip o
WHERE o.owner IN (''HR'', ''SCOOT'')
AND o.object_type IN (''TABLE'', ''PROCEDURE'', ''FUNCTION'', ''PACKAGE'')
*/
-- DBMS_OUTPUT.PUT_LINE (V_DYNSQL);
EXECUTE IMMEDIATE v_dynsql;

COMMIT;
--mail atan procedureyi çagiralim.
smtp_att_mail ('CRE_OR_DEL_OBJECT');

--Mail atma islemini tablodan yaptigimiz için gerek kalmadi.
--Burada tabloyu text dosyaya yazan procedureyi cagiriyorum.
-- EXTRACT_TABLE ('CRE_OR_DEL_OBJECT', --tablo adi
-- ',', --ayracimiz
-- 'USERDATA_DB', --directory
-- 'DELETE_AND_CREATE.TXT' --dosya adi
-- );
EXECUTE IMMEDIATE 'TRUNCATE TABLE OBJECT_TAKIP';

INSERT INTO object_takip
(owner, object_name, object_type)
SELECT owner, object_name, object_type
FROM all_objects
WHERE owner IN ('HR', 'SCOOT')
AND object_type IN
('PROCEDURE', 'PACKAGE', 'TABLE', 'VIEW', 'FUNCTION');

COMMIT;
END;
/

ORACLE PL /SQL İLE ATTACHMENT MAİL GÖNDERME

ORACLE ile mail atmak için aşağıdaki yöntemi izleyebilirsiniz. Size attachment'li mail atma desteği verecektir.


CREATE OR REPLACE PROCEDURE smtp_att_mail (
pin_table_name IN VARCHAR DEFAULT 'CRE_OR_DEL_OBJECT'
)
IS
--gönderen kısmında yazacak olan yaz bu alan gecerli olmak zorunda değildir.

v_from VARCHAR2 (80) := 'OBJE.BILGILERI@aliates.com';
v_recipient VARCHAR2 (80) := 'aliatesh@hotmail.com';
v_subject VARCHAR2 (80) := 'olusan ve silinenler nesneleri listeler.';
v_mail_host VARCHAR2 (30) := 'mailserver';
v_mail_conn UTL_SMTP.connection;
crlf VARCHAR2 (2) := CHR (13) || CHR (10);
--mesaj VARCHAR2 (4000) NULL;
--dosyamızın içerisinde yazacakları bir değişkende topluyorum.
--burada VARCHAR2 kullandım ama long da kullanılabilinir.
mesaj VARCHAR2 (30000) := '||';
BEGIN
--burada tabloyu değişkene aktarıyorum.
--dikkat etmek gereken konu burada mail içeriğine uygun olması gerektiğidir.
--bunun için biraz denemeler yapmaız gerekebilir.
--ben substr ile istemediğim alanları kesitim. Siz daha orijinal bir çözüm üretirsiniz artık.
FOR i IN (SELECT *
FROM user_objects where rownum<10)
LOOP
mesaj :=
mesaj
|| ''
|| i.owner
--burada ";" kullanıyorum ki Excell bunu otomatik olarak algılasın ve sütün sütün göstersin.
--bu parametreyi control panelden de değiştirenbiliyorsunuz. isterseniz burada "|" yada "," kullanabilirsibiz.
|| ';'
|| i.object_name
|| ';'
|| i.object_type
|| ';'
|| i.status
|| crlf;
END LOOP;

mesaj := SUBSTR (mesaj, 3, (LENGTH (mesaj) - 2));
--burada 25. portu kullanarak mail gönderme parametlerini veriyorum.
v_mail_conn := UTL_SMTP.open_connection (v_mail_host, 25);
UTL_SMTP.helo (v_mail_conn, v_mail_host);
UTL_SMTP.mail (v_mail_conn, v_from);
UTL_SMTP.rcpt (v_mail_conn, v_recipient);
UTL_SMTP.rcpt (v_mail_conn, 'aliatesh@hotmail.com');
--buraya birden fazla mail adresi ekleyebiliriz.
--bu fonksiyon için parametre alan bir dongu yazılabilir.
UTL_SMTP.rcpt (v_mail_conn, 'aliatesbilgisayar@yahoo.com');
--Mail içeriği burada aslında
UTL_SMTP.DATA
(v_mail_conn,
'Date: '
|| TO_CHAR (SYSDATE, 'Dy, DD Mon YYYY hh24:mi:ss')
|| crlf
|| 'From: '
|| v_from
|| crlf
|| 'Subject: '
--başlığımızı belirtiyoruz.
|| v_subject
|| crlf
--burada TO : yazmasını istediğimiz yazıyoruz.
--dongu ile buraya otomatik parametre eklenebilir.
|| 'To: adi bende sakli'
|| crlf
|| 'MIME-Version: 1.0'
|| crlf
||
'Content-Type: multipart/mixed;'
|| crlf
|| ' boundary="-----SECBOUND"'
|| crlf
|| crlf
|| '-------SECBOUND'
|| crlf
--içeriğin tipinide burada girdik.
|| 'Content-Type: text/plain;'
|| crlf
|| 'Content-Transfer_Encoding: 7bit'
|| crlf
|| crlf
|| 'Bu bir bilgilendirme mailidir. Günlük olarak silinen ve yeni olusturulan database objelerini bildirir.'
|| crlf
--mesaj içerisinde yazmak istediğiklerimiz.
||
'Dosya ektedir Bilginize'
|| crlf
|| crlf
|| '-------SECBOUND'
|| crlf
|| 'Content-Type: text/plain;'
|| crlf
|| ' name="excel.csv"'
|| crlf
|| 'Content-Transfer_Encoding: 8bit'
|| crlf
|| 'Content-Disposition: attachment;'
|| crlf
--oluşan dosyaya vereceğimiz isim.
|| ' filename="silinen_olusan.csv"'
|| crlf
|| mesaj
|| crlf
|| '-------SECBOUND--'
);
UTL_SMTP.quit (v_mail_conn);

EXCEPTION
WHEN UTL_SMTP.transient_error OR UTL_SMTP.permanent_error
THEN
raise_application_error (-20000, 'Unable to send mail: ' || SQLERRM);
END;
/

Monday, July 6, 2009

TABLESPACE YARATMA SCRİPT'İ

Var olan bir tablespace'nin scriptini aşağıdaki kod yardımı ile üreyebilirsiniz. Bu nerede işimize yarayabilir sorusuna verilecek ilk cevaplardan biriside database import ederken aynı özelliklerde bir tablespacemiz olmuş olur. Yada denemeler yapmak için kendimize bir test datadabase'i oluşturacağiz. O zaman aşağıdaki kod bloğu yardımı ile aynısını oluşturabiliriz.
--çıktı dosyamızı ayarlayalım.
spool tablespace_olustur.sql
set serveroutput on size 1000000
/* Formatted on 2009/07/06 10:24 (Formatter Plus v4.8.8) */
DECLARE
CURSOR get_ts
IS
SELECT *
FROM dba_tablespaces
WHERE tablespace_name != 'SYSTEM';

CURSOR get_df (p_ts VARCHAR2)
IS
SELECT *
FROM dba_data_files
WHERE tablespace_name = p_ts;

l_str VARCHAR2 (10);
BEGIN
FOR ts_rec IN get_ts
LOOP
DBMS_OUTPUT.put_line ('CREATE TABLESPACE ' || ts_rec.tablespace_name);

-- tablespace de bulunana bütün datafile leri burada yaz.
FOR df_rec IN get_df (ts_rec.tablespace_name)
LOOP
IF get_df%ROWCOUNT = 1
THEN
l_str := 'DATAFILE';
ELSE
l_str := ',';
END IF;

DBMS_OUTPUT.put_line ( l_str
|| ' '
|| CHR (39)
|| df_rec.file_name
|| CHR (39)
|| ' SIZE '
|| df_rec.BYTES
|| ' REUSE '
);

IF df_rec.autoextensible = 'YES'
THEN
DBMS_OUTPUT.put_line ( ' AUTOEXTEND ON'
|| ' NEXT '
|| df_rec.increment_by
);

IF df_rec.maxbytes = 68719443968
THEN
DBMS_OUTPUT.put_line (' MAXSIZE UNLIMITED');
ELSE
DBMS_OUTPUT.put_line (' MAXSIZE ' || df_rec.maxbytes);
END IF;
END IF;
END LOOP;

/* Extent Management durumuda burada. */
DBMS_OUTPUT.put_line ('EXTENT MANAGEMENT ' || ts_rec.extent_management);

IF ts_rec.extent_management = 'LOCAL'
THEN
IF ts_rec.allocation_type = 'SYSTEM'
THEN
DBMS_OUTPUT.put_line (' AUTOALLOCATE ');
ELSE
DBMS_OUTPUT.put_line (' UNIFORM SIZE ' || ts_rec.initial_extent);
END IF;
END IF;

IF ts_rec.extent_management = 'DICTIONARY'
THEN
DBMS_OUTPUT.put_line ( 'DEFAULT STORAGE (INITIAL '
|| ts_rec.initial_extent
|| ' NEXT '
|| ts_rec.next_extent
|| ' MINEXTENTS '
|| ts_rec.min_extents
|| ' MAXEXTENTS '
|| ts_rec.max_extents
|| ' PCTINCREASE '
|| ts_rec.pct_increase
|| ' ) '
);
END IF;

DBMS_OUTPUT.put_line (' ONLINE;');
DBMS_OUTPUT.new_line;
END LOOP;
END;
/
spool off
--kodlar hazır.