Updates from Mart, 2016 Toggle Comment Threads | Tuş takımı kısayolları

  • dutali 1:04 am on 2016-03-21 Kalıcı Bağlantı | Cevapla
    Tags: duplicate, having, mükerrer, partition by, pk, rowid, row_number, tekrarlayan, tekrarsız   

    Tablodaki mükerrer kayıtları silme 

    Veri kalitesi problemlerinin önemli bir kısmı tablolardaki tekrarlı kayıtlardır
    Burada mükerrerden kastımız PK, ya da diğer  tekrarsız anahtarların tekrar etmesi , veya tüm satırın olduğu gibi tekrar etmesidir

    Mükerrer veriyi silmeden önce mükerrerden kastımızı net bir şekilde anlamamız ve geçerli kayıt ile geçersiz kayıt ayrımını neye göre yapacağımızı bilmemiz gerekir
    Burada önemli bir nokta; Eğer mükerrerlik bütün satırın aynen tekrar etmesi şeklinde ise  silinecek kaydı ayıracak bir sütun  (pseudo kolonlar hariç) bulunmaz.

    Yöntemimiz, ROWID sahte kolonunu ( pseudo column) kullanarak mükerrer kayıtları işaretlemek ve silmek şeklinde olacak. Geçerli kaydı diğerlerinden ayırmak için
    ROW_NUMBER sözcüğü ile tekrarlayan kayıtları sıralayacağız.

    Aşağıda anlatacağımız yöntemde ROWID kullanılmasının özel bir işlevi var.
    Tekrarlı kayıtları birçok şekilde işaretleyebilirsiniz. Silme aşamasında silinecek kaydı ayrımak için uyguladığınız koşul gerçek kayıt ile de birebir uyuşabilir.
    Bu durumda ilgili kaydı bütün kopyeleri ile silmiş olursunuz -ki farketmesk de güç olabilir. Mesela kayıtlar birebir tekrarlıyor ise ayırmanız olanaksızdır

    Sorgumuzu hazırlamak üzere örnek olarak  bir firmanın şubelerini ve yetkililerinin bilgilerini tutan şu tabloya bakalım

    SELECT * FROM firma_sube

     

    Örnek tablo- Firmanın  şubeleri

     
    Bu tablo firma şubeleri bazında, yani her şube için tek bir kayıt olması bekleniyor. Anahtar kolon sube_id olarak . sube_kisa_ad sütunu da gene sube_id gibi tekrarsız
    Tabloda, firmanın her bir şubesi için o şubenin yetkilisi, telefon numarası ve yetkilinin performans puanı bilgisi bulunuyor. Ayrıca her kaydın eklendiği tarih de kayit_ekleme_tarihi sütununda tutuluyor
     
    Tabloda, zaman içinde eski kayıtlar silinmeden yeni kayıtlar eklenerek veya yanlışlıkla aynı kayıt iki kere girilerek mükerrer kayıtlar oluşturulmuş. Bazı kayıtlar birebir aynı!

    –Şube_id bazında mükerrer kayıtlara bakalım. Önce her şube id’nin kaç kere tekrar ettiği ..

     

    Birden fazla tekrarlananları filtreleyelim

      SELECT sube_id, COUNT (*) AS adet
        FROM firma_sube
    GROUP BY sube_id
    HAVING COUNT(*)>1

    Bu sorgu ile aşağıdaki sorgu denktir

    SELECT *
      FROM (  SELECT sube_id, COUNT (*) AS adet
                FROM firma_sube
            GROUP BY sube_id)
    WHERE adet > 1 
     

    Mükerrer kayıtları süzme-Having sözcüğü
     
    –14 sube_id için birden fazla kayıt var.

    –şimdi sıra geldi mükerrer olanlardan biri hariç diğerlerini silmeye. Silme işlemine geçmeden önce tekrarlayan kayıtlardan ahngisini silmem gerektiğini nasıl belirleyeceğimi bilmem gerekir.
    Biz örnek olarak son kayıdı en geçerli kayıt olarak alacağız. Aynı kayıdın tekrarlaması durumunda ise herhangi biri zaten uygundur.

    Başlayalım. Önce kayıtları numaralandırarak sonucunu görelim

    SELECT s.ROWID AS row_id
         , s.*
         , ROW_NUMBER ()
              OVER (PARTITION BY s.sube_id ORDER BY s.kayit_eklenme_tarihi DESC) AS rn
      FROM firma_sube s 

    Mükerrer kayıtları işaretleme- row_number-rowid
     

    Buradaki row_number deyimini açalım.
        sube_id bazında tekillik istiyoruz . PARTITION BY sözcüğünün yanına sube_id yi koyduk. Tekillik başka kolonlardan olsaydı,
    mesela sube_id ve yetkili_adi bazında tekrarsız olması gerekseydi PARTITON BY sube_id, yetkili_adi yazardık
        en yeni kaydın geçerli kayıt olmasını istiyoruz. ORDER  BY sözcüğü yanına kayit_ekleme_tarihi sütununu yazıyoruz. Fakat geçerli kayıt dışında birçok kayıt olabilir. Geçerli kayıtın row_number değeri her zaman 1 olmalı
        Bu sebeple sıralamayı ters yapıyoruz  ( DESC sözcüğü)
        
     
    Silmeden önce kayıtları görmekte fayda var. rn değeri 1 olmayan kayıtları rowid değerinden ayırıyoruz. rowid ile ayrımak bize, aynı kayıdın birebir tekrar etmesi durumunda bile bir kaydı koruma imkanı veriyor

    SELECT *
      FROM (SELECT s.ROWID AS row_id
                 , s.*
                 , ROW_NUMBER ()
                   OVER (PARTITION BY s.sube_id
                         ORDER BY s.kayit_eklenme_tarihi DESC)
                      AS rn
              FROM firma_sube s) baz
    WHERE baz.rn <> 1

    Silinecek tekrarlı kayıtlar

    Şimdi bu kayıtları silelim

     

     

    DELETE FROM firma_sube
    WHERE ROWID IN (SELECT row_id
                       FROM (SELECT s.ROWID AS row_id
                                  , s.*
                                  , ROW_NUMBER ()
                                    OVER (PARTITION BY s.sube_id
                                          ORDER BY s.kayit_eklenme_tarihi DESC)
                                       AS rn
                               FROM firma_sube s) baz
                      WHERE baz.rn <> 1) 
     

     

     

    ! Dikkat!  ROWID sanal sütunu (presudo column) her satır için farklı ve tekrarsızdır. ROWNUM sütunu ile karıştırılmamalıdır. ROWNUM sanal sütunu sorgu sonucunda üretilir ve değişkendir

     

    ROWID ile filtrelemek yerine kayit_ekleme_tarihi değerini çekerek ve numaralandırarak , o değere ve sube_id’ye uyan kayıtları silebilirdik. Fakat bazı kayıtlar tamamen aynı olabilir. O zaman kayit_ekleme_tarihi ve sube_id değerinin uyuştuğu kaydı da silmiş, başka bir hata yapmış olurduk. Bahsettiğimiz durumu ifade eden sql şöyle olabilir;

     

    —-Hatalı sql- örnek

    –DELETE FROM firma_sube
    –      WHERE (sube_id, kayit_ekleme_tarihi) IN (SELECT sube_id
    –                                                    , kayit_eklenme_tarihi
    –                                                 FROM (SELECT s.*
    –                                                            , ROW_NUMBER ()
    –                                                              OVER (
    –                                                                 PARTITION BY s.sube_id
    –                                                                 ORDER BY
    –                                                                    s.kayit_eklenme_tarihi DESC)
    –                                                                 AS rn
    –                                                         FROM firma_sube s)
    –                                                WHERE rn = 1)

     
  • dutali 12:52 am on 2016-02-22 Kalıcı Bağlantı | Cevapla
    Tags: OFA, Optimal Flexible Architecture, oracle_base, oracle_home, oui   

    Oracle’ı nereye kuralım – Optimal Flexible Architecture (OFA) 

    Linux üzerinde Oracle veritabanı kuracaksanız kurulumu nereye yaparsınız? Kök dizinde bir klasör mü yaratırsınız yoksa kullanıcı klasörünü mü seçersiniz? Kurulumu ayrı bir partition’a mı kurarsınız kullanıcıların dosyalarının veya sistem dosyalarının olduğu partition’a mı? Kurulum için seçtiğiniz yol ve partition ne kadar önemli? Diski nasıl parçaladığınız performansı ne kadar etkiler?

    OFA (Optimal Flexible Architecture.Türkçesi ile : En uygun esnek mimari ) Oracle veritabanı kurulumu için Oracle’ın takip edilmesini önerdiği birtakım standartlar bütünüdür. Standartlar, oracle kurulum klasörlerini isimlendirilmesi, veritabanı dosyalarını isimlendirilmesi, disk partition yapısının belirlenmesi gibi konularda kurallar içerir.

    Peki ne işe yarar?

    Veritabanının ve sistemin bakım işlemlerini kolaylaştırır ve maliyetlerini düşürür
    Performansının yüksek olmasına yardım eder
    Gerektiğinde aynı mimaride genişletilebilmesi imkanını verir

    Oracle universal installer (OUI) sistem üzerinde işlemler yaparken öncelikle OFA standartlarına uygun klasör yapısı olup olmadığına bakar. Var ise ne ala. OUI tarafından yaratılacak olan diğer klasör yolları OFA standartlarına uygun olacaktır. Yoksa atanan çevre değişkenlerine de bağlı olarak yaratacağı dosya-klasör yollarına karar verir.

    İdeal durumda OUI, kök dizinde u01,u02 gibi isimlendirilmiş ve mount point olan klasörler bekler. Kurulumun ayrı bir disk birimi üstünde olması önemlidir. Bu şekilde oracle dosyaları sistem dosyalarından ve kullanıcıların dosyalarından ayrık bir halde durur . Bu, hem sistem performansı ve disk kapasitelerinin karşılıklıetkilememesi için önemlidir hem de bakım-yedekleme ve geri yükleme prosesleri için hayati değerdedir
    İsimlendirme standart olduğundan ve kuralları, unix sistemlerdeki FSH ( Filesystem Hierarchy Standard ) standartlarına benzediğinden, sistem kullanıcıları klasör yollarına ve ihtiyaç duydukları dosyalara daha kolay erişirler

    OFA ‘ya uygun kurulumda;

      • Dosya sistemindeki bütün bağlantı noktaları (mount point) /pm sentaksına göre adlandırılmalı.

    Burada;
    p :herhangi bir metin ,
    m : numaralandırmak maksatlı sayı.

    Mesela /part01, /part02 gibi veya varsayılan olarak /u01, /u02 gibi olmalı

    • Oracle base klasörü /pm/h/u sentaksına göre isimlendirilmeli. Dikkat! Oracle Base klasörü birden çok oracle uygulamasına ev sahipliği yapabilir

    Burada;

    pm :bağlanma noktası ( mount point).
    h :standart klasör ismi ( app gibi)
    u : kurulumu gerçekleştiren işletim sistemi kullanıcısıdır.

    Oracle kullanıcısı ile kurulum yaptı iseniz Oracle base şu şekilde olacak: /u01/app/oracle .

    • Oracle home klasörü, birden fazla oracle ürünü veya sürümünün kurulumunda şu desene göre verilmeli
      /pm/h/u/product/v/type_[n].

    Burada;

    pm : bağlanma noktası
    h : standart klasör ismi (app gibi)
    u : kurulumu gerçekleştiren işletim sistemi kullanıcısı
    v :uygulamanın versiyonu
    type: kurulan uygulamanın tipi, n ise aynı uygulama birden fazla kurulabileceği için verilen numaradır. Ör: veritabanı ise db_1, db_2, client için client_1, client_2

    • Veritabanı performansını ve güvenilirliğini artırmak için bileşenler farklı disklere dağıtılmalı. Bunun için şeritli birimlerden (striped volume) ve aynalanan birimlerden (mirrored volume) oluşan diskler kullanılabilir.
      ASM kullanıyorsanız bu şartlar zaten sağlanıyordur.

     

    Şimdi OFA standartlarına uygun olarak ve oracle kullanıcısı ile gerçekleştirilen standart kurulumda oluşan örnek klasör yollarına bakalım

      • Oracle Base klasörü

    /u01/app/oracle

      • Birden fazla uygulama varsa bu uygulamaların home dizinleri

    /u01/app/oracle/product/11.1.0/db_1
    /u01/app/oracle/product/11.2.3/db_2
    /u01/app/oracle/product/11.2.3/crs

      • Veri dosyaları diğer bağlanma noktalarına dağıtıldığında veri dosyalarının yolu ( veri dosyalarını dağıtmak tercih edilir ise)

    u02/app/oracle/oradata
    /u03/app/oracle/oradata
    /u04/app/oracle/oradata

      • Başka kullanıcılar tarafından kurulan başka oracle uygualamaları için Oracle Base klasörü

    /u01/app/diger_kullanici/

      • Orainventory dosyasının konumu;

    /u01/app/oraInventory

    şeklinde olur.

     
  • dutali 4:38 am on 2016-02-07 Kalıcı Bağlantı | Cevapla
    Tags: bulk collect fetch forall oracle   

    Büyük hacimli verileri yükleme – Bulk insert 

    Çok büyük hacimli tablolardan veri çekme ve yükleme, eğer kaynak tablo doğru partition yapısında ve doğru şekilde indekslenmemiş ise makinanın gücüne göre çok yavaş olabilir

     

    Böyle bir durumda PL-SQL in çok önemli bir özelliği olan BULK COLLECT ifadesi kullanılarak yükleme yapılabilir. Bu  ifade ile birlikte INSET, UPDATE, MERGE ve DELETE ifadeleri kullanılabilir. Birçok başka kullanım şekli ve amacı da var ama biz kısıtlı olarak nasıl büyük hacimli verilerde performans sağladığıyla ilgileneceğiz

     

    Tabii ki başka yollarla da performans artışı şağlanabilir. Mesela kaynak tablo üzerinde uygun şekilde  partition oluşturma ve indeksleme yapmak, sorguyu (mümkün ise) daha verimli hale getirmek, PL-SQL döngüsü ile veriyi parça parça çekmek, sorguya uygun hint yazmak , pipelined table functions ( türkçe önerisi olan?) veya bunları birlikte yapmak.

    Fakat kaynak tablonun hacmi fiziksel hafızadan çok daha büyük olduğu bir durum düşünün. Veriyi tek bir set halinde çekmek ve işlemek diğer çalışanları da zor durumda bırakacaktır. BULK COLLECT ifadesi bu durum için iyi bir çözüm. Çünkü veriyi LIMIT ifadesi ile sınırlanan birden parçalar halinde çeker ve işler. Buna alternatif olarak kaynak tabloya partition eklenip gene PL-SQL döngüsü ile veriyi parça parça yükleyebilirsiniz. Fakat gene de her seferinde devasa bir tabloya filtre uygulamak zorunda kalırsınız.

    Peki her seferinde veriyi filtrelemeden parçalar halinde işlemenin yolu yok mu? rownum kullanılamaz mı? Hayır.  Oracle, rownum değerini veri setini ürettikten sonra koyar. MySQL bilenler için garip bir eksiklik olarak görülebilir

     

    Şimdi örneğimize geçelim. Örneğimiz oe.orders tablosundan dw.fct_orders tablosuna 10.000 er parçalar halinde veri yükleyecek

     

    DECLARE
    TYPE t_order_raw_data IS TABLE OF dw.fct_orders%ROWTYPE
    INDEX BY BINARY_INTEGER;
    l_order_raw_arr   t_order_raw_data;
    l_chunk_size      NUMBER := 20000;
    CURSOR order_raw_cur  IS
    SELECT /*+ PARALLEL(f 16)*/
    FROM oe.orders f;
    BEGIN
    OPEN order_raw_cur;  LOOP
    FETCH order_raw_cur
    BULK COLLECT INTO l_order_raw_arr
    LIMIT l_chunk_size;
    EXIT WHEN order_raw_cur%NOTFOUND;
    FORALL i IN INDICES OF l_order_raw_arr SAVE EXCEPTIONS
    INSERT INTO dw.fct_orders
    VALUES l_order_raw_arr (i);

    END LOOP;

       CLOSE order_raw_cur;
    END;

     
  • dutali 1:49 am on 2016-02-07 Kalıcı Bağlantı | Cevapla
    Tags: oracle manually_delete linux centos uninstall deinstall elle_kaldırma manuel_kaldırma   

    Linux makinada Oracle ‘ı manuel olarak tamamen kaldırma 

    Oracle veritabanını kurmak kadar kaldırmak ta bir problem olabilir. Eğer oracle veritabanını kaldırmanın kolay olduğunu düşünen birini görürseniz ya çok mütevazidir ya da daha kaldırma gereği duymamıştır.

    Özellikle sistemde birden fazla oracle ürünü kuruluysa ve de kurulumlar standart klasör yolları ve en uygun ayarlar ile yapılmamış ise risk katlanılmaz olabilir.  Daha da kötüsü veritabanı ciddi hasar görmüş ise  deinstall scriptleri çalışmıyor ise ..

    Böyle bir durumda tercih edilebilecek yok veritabanı uygulamasını ve instanceları  elle kaldırmak olacaktır.

    Örnek olarak Centos 6.5 üzerinde standart klasör yapısı ile kurulmuş bir oracle veritabanı uygulamasının ve buna bağlı instanceların kaldırılmasını inceleyelim.

    Öncelikle

    • Klasik yollarla kaldırmayı deneyin  ( deinstall script).Başarılı olursanız bu reçeteyi çöpleri temizlemek için takip edin.
    • Kaldırma işlemine başlamadan önce usr/local/bin/oraenv  dosyasını, etc/oraInst.loc dosyasını , /u01/app/oracle/oraInventory dosyası gibi kritik dosyaları ve veritabanından kurtarabileceğiniz verileri ( ya da veri dosyalarını) yedekleyin
    • Bazı dosyaları silebilmek için root yetkisine ihtiyacınız olacak. root yetkisine sahip olduğunuzan emin olun.
    • Herhangi bir dosyayı silmeden önce o dosyanın ilgili klasörde olduğuna emin olun! Bazı kurulumlarda dosya yolları farklı olabilir, dosya isimleri değişik olabilir.!  Toplu silme işlemi yapmadan önce dosyaları listeleyip neyi sildiğinizden emin olun!
    • Her yaptığınız işlemi kaydedin
    • Birden fazla reçeteyi takip ederek yaptığınız işlemden emin olun
    • Her ne kadar aşağıdaki işlemler defalarca denemiş olsa da her durumu karşılamayabilir.
    • Dikkatli olun!

    Dikkat! Sistemde kurulu başka oracle uygulaması var mı? Diğer uygulamalara zarar vermemek için yazıyı dikkatle okumadan komutları çalıştırmayın. Oracle veritabanı uygulamasını değil de sadece tek bir oracle instance ‘ı kaldıracaksanız bu reçete size göre değil!!

     

    • Öncelikle çalışan oracle veritabanı instance  ve listener var ise durdurun. Eğer durduramıyor iseniz proseslerden oracle instance ı bulun ve kill komutu ile öldürün. Bunun için isteme root yetkileri ile girmenizde fayda var.

    ! Başka oracle uygulamaları da var ise komutu daha dikkatli kullanın. Diğer prosesleri öldürmeyin!

      Örnek:

    Oracle instanceları ve listenerları bulup öldürmek için  ps komutu ve öldürmek içik kill komutu ..  Oracle kullanıcısı ile kurulum yapıldığı için instanceları rahatlıkla ayırabiliyoruz

    #ps -aef | grep lsnr

    oracle 17935 1     0 2013  /u01/app/11.1.0.7/.. LISTENER

    root   97983 81338 0 2013 grep lsnr

    kill –9 17935

    #ps –ef | grep  ora_

    oracle   111345    1  0 2013   ora_pmon

    oracle   135789    1  0 2013   ora_smon

    ..

    #kill –9 111345 135789

    ! Proses isimleri kurulumdan kuruluma farklılık gösterebilir. Kendi kurulumunuza ait proses isimlerini ve desenini öğrenin

    • ORACLE_HOME dizinini ve altındaki her şeyi silin

    Burada ORACLE_HOME oracle veritabanının home dizinidir. Başka oracle uygulamaları kurulu ise ORACLE_HOME çevre değişkeni değiştirilmiş olabilir.

    Genel olarak oracle veritabanı için ORACLE_HOME

    /u01/app/oracle/product/11.2.0/dbhome

    veya daha kötü bir kurulumda

    /oracle/ora_apps/oradb/product/11.1.0/dbhome

     

    gibi bir klasör yolundadır

    Örnek:

    # rm -rf /u01/app/oracle/product/11.1.0/dbhome_1

    • Oracle veritabanının zamanlanmış görevlerini (cron job) kaldırın .

    var/spool/oracle

    dosyasında oracle uygulamalarının zamanlanmış görevleri bulunur.  Önce içinde ne var bakın

    Ör:

    [root@localhost cron]# cat oracle
    0,15,30,45 * * * * /u01/app/oracle/product/11.1.0/dbhome/.. -cron -silent start

    0,15,30,45 * * * * /u01_apps/oracle/odi/ … 

    Başka oracle uygulaması yüklü değilse bu dosyayı silin!! 

    # rm -rf /var/spool/oracle

    Fakat yukarıdaki örnekte ikinci satırda oracle veritabanı değil ODI için zamanlanmış görev de var.

    Bu durumda yapmamız bu dosyayı açarak sadece veritabanı zamanlanmış görevi bulunan satırları silmek

    • /etc klasörüne girin. Bu klasörde oracle ile ilgili iki tane dosya göreceksiniz . Bu  dosyalar ora ile başlar !

    [root@localhost /]# ls -l /etc/ora*
    -rw-r–r– 1 root root 32 Jan 9 2014 /etc/oracle-release
    -rw-rw-r– 1 oracle oracle 734 Jan 2 08:53 /etc/oratab
     

      oracle-release dosya işletim sisteminin oracle-linux versiyonunu gösterir ( oracle linux a çevirdi iseniz). Bu dosyaya dokunmayın!
      oratab dosyasında sistemdeki oracle veritabanı uygulamalarını ve bunlara bağlı veritabanı instanceları bulunur. Biz şimdi tüm veritabanı ve uygulamalarını kaldırmak istediğimizden bu dosyayı sileceğiz.

    #rm -rf etc/oratab

    ! Bu dosyayı kaldırmak için root yetkisi gereklidir!

    ! Bazı kurulumlarda bu dosya /var/opt/oracle altında olabilir

    • Oracle çevre değişkeni dosyalarını silin </LI>

    #rm -f /usr/local/bin/coraenv
    #rm -f /usr/local/bin/oraenv
     

    • Eğer tüm oracle uygulamalarını kaldıracaksanız tüm oracle uygulamaları tarafından kullanılan şu dosyayı silin

    # rm -rf /etc/oraInst.loc

    ! Bu dosyayı kaldırmak için root yetkisi gereklidir!

    • OraInventory dosyasını silin

    # rm –rf  /u01/app/oracle/oraInventory

    Bu dosya ne işe yarar? http://gerardnico.com/wiki/database/oracle/orainventory

    Bu dosya temiz kurulum yapmak için çok kritik. tek bir kurulum olan makinada dbhome_2 gibi isimlerin sorumlusu işte bu dosya.Önceki kurulumun nerede izi kaldı diye arıyorsanız ilk bakmanız gereken yer burası!!

        Tertemiz makinamız hazır.

     
  • dutali 4:35 pm on 2015-03-11 Kalıcı Bağlantı | Cevapla
    Tags: database, null, oracle   

    Oracle veritabanında NULL 

    Basitçe değer yok anlamında bir ifade : NULL . Nümerik ya da karakter formatında değil; bir tipi ya da uzunluğu yok. Değer yok anlamında ama gene de bir değer.

    Özellikle bazı işlemlerde dikkat edilmediğinde sürpriz hatalara sebep olabilir. Mesela iki tabloyu birbiri ile bitiştiriyorsanız ve kolonların NULL olma olasılığı varsa , sorgularınızda NOT EXIST , NOT IN gibi ifadeler kullanıyorsanız, karşılaştırma operatörleri ile bir koşulun sağlanıp sağlanmadığını kontrol edecekseniz , NULL değer barındıran kolonlarla sayısal işlemler yapıyorsanız … NULL değerler sesebiyle hatalı sonuç üretme riskiniz doğar

    SQL dilinde NULL tipsiz bir değerdir. 0, 4 gibi bir sayı ya da bir metin değildir.Genel olarak NULL ile yapılan her işlem NULL değer döndürür. NULL bir değer ile toplama çıkarma vs işlemleri yapılamaz ve çoğu fonksiyon ile birlikte kullanılamaz. NULL ın bir tipi olmadığından herhangi bir değer ile hatta kendisi ile dahi karşılaştırılamaz. Bu sebeple NULL ile karşılaştırma işlemlerinde =, <> operatörleri değil IS -IS NOT kullanılmalıdır. NULL ın hayatı zorlaştıran bu özelliklerine binaen oracle da NVL, NVL2, NULLIF, NNVL gibi sırf NULL ile başetmek için fonksiyonlar yaratılmıştır.

    Matematiksel ifadelerdeki etkisinden başlayalım. 0 ve NULL ve ” ne kadar benzer. Öncelikle;

    SQL>SELECT ''
         , NULL
         , ' '
         , NULL || NULL
      FROM DUAL;
    
    

    Eğer kullandığınız editörü özellikle NULL değerleri NULL ile doldur diye ayarlamadıysanız bu sorgudan size bomboş bir satır dönecek. Biraz görünür yapalım;

    SQL>SELECT DUMP ('')
         , DUMP (NULL)
         , DUMP (' ')
         , DUMP (NULL || NULL)
      FROM DUAL;
    
    DUMP('')            DUMP(NULL)          DUMP(' ')	                DUMP(NULL||NULL)
    NULL	            NULL	        Typ=96 Len=1: 32                   NULL
    

    Burada dikkat etmeniz gerken şey iki tırnak arasına hiçbir şey yazdaman sorgu yazdığınızda da ( ” ) NULL sonuç döndürmüş oluyoruz!

    Ascii kodları;

    SQL>SELECT ASCII ('')
         , ASCII ('''')
         , ASCII (NULL)
         , ASCII (' ')
         , ASCII (NULL || NULL)
      FROM DUAL;
    
    ASCII('')	ASCII('''')	ASCII(NULL)	ASCII('')	ASCII(NULL||NULL)
    34	            39		                  32	
    

    Evet. Gördüğünüz gibi NULL bir karakter olmadığından ASCII karşılığı da yok.

    Şimdi şu basit sorguyu ele alalım

    SQL>  SELECT 0 * 5, NULL * 5,
                 0 + 5, NULL + 5   
            FROM DUAL;
    
    0*5 NULL*5 0+5 NULL+5
    ---- ------ ---- --------
    0 NULL 5 NULL
    
    

    0 ın toplamada etkisi yok. Ama NULL toplama işlemi sonucunu dahi NULL yapar. Sıfır ile tanımsız bir işlem yaptığınızda hata alırsınız ama NULL ile hata almazsınız. Sonuç hep NULL çıkar.

    SQL>SELECT NULL / NULL , 5 / NULL ,
                ROUND (NULL / NULL + 1, 2) ,
                NULL * 0 , NULL * NULL ,
                ABS (NULL) , ADD_MONTHS (NULL, 5),
                LOG (5, NULL) , TRUNC (NULL)
           FROM DUAL;
    
    NULL NULL NULL NULL NULL NULL NULL NULL NULL
    

    Aritmetik operatörlerle kullanıldığında yanındakilere hiç acımıyor. Aynı sorguyu NULL yerine 0 ile yazmak isterseniz çoğu durumda hata alırsınız, Mesela 5/0 tanımsızdır ..

    Bir değerin NULL olup olmadığı eşitlik operatörü ile yapılamaz. Bunun için IS -IS NOT kullanılır. Şu iki sorguya bakalım

    SQL> SELECT
          CASE WHEN NULL = NULL THEN 'NULL eşittir NULL'
           ELSE 'NULL eşit değildir NULL'
          END FROM DUAL;
    
    NULL eşit değildir NULL
    
    SQL>SELECT CASE
                WHEN NULL IS NULL THEN 'NULL eşittir NULL'
                ELSE 'NULL eşit değildir NULL'
               END FROM DUAL;
    
    NULL eşittir NULL
    

    Burada NULL değer olarak içeriği boş bir değişken de olabilirdi. Zaten hata da genelde bu durumda olur

    NULL olabilecek bir kolonda karşılaştırmada NVL gibi fonksiyonlar yardımıyla olası hatalardan rahatlıkla kaçınılabilir. Riskli olan şey herhangi bir kolonun NULL olup bu kolonun EXIST- NOT EXIST, IN- NOT gibi ifadelerde kullanılması.

    Örnek bir tablo yaratalım ve hemen birkaç sorgu çekelim

    SQL>CREATE TABLE null_test ( id NUMBER , a NUMBER , b NUMBER);
    
    INSERT INTO null_test VALUES ( 1, 10, 10);
    INSERT INTO null_test VALUES ( 2, 20, 20);
    INSERT INTO null_test VALUES ( NULL, 30, 30);
    INSERT INTO null_test VALUES ( 4, 50, NULL);
    COMMIT;
    
    SQL>SELECT * FROM null_test;
    
    
    SQL>SELECT SUM (a) FROM null_test;
    
    110
    
    SQL>SELECT SUM (a) FROM null_test
         WHERE a NOT IN (SELECT NULL from DUAL);
    
    NULL
    
    SQL>SELECT SUM (a) FROM null_test t1
         WHERE NOT EXISTS (SELECT NULL FROM DUAL );
    NULL
    

    Burada SELECT NULL FROM DUAL yerine sonucu NULL değerdöndüren herhangi bir sorgu olabilir.

    Dikkat. NOT IN ifadesi hiç değer döndürmüyorsa sorgu gene doğru sonuç verir. Hata , içteki sorguda herhangi bir değerin NULL olmasından kaynaklanır. Mesela aşağıdaki sorgu sonucu değer döndürmez fakat yukarıdaki gibi sonuç NULL dönmez.

    SQL>SELECT SUM (a) FROM null_test
         WHERE a NOT IN (SELECT a FROM null_test WHERE 1 = 0);
    
    110
    
    SQL>SELECT SUM (a) FROM null_test t1
          WHERE NOT EXISTS (SELECT a FROM null_test WHERE 1 = 0);
    
    110
    

    Bu sorgu da SELECT a FROM null_test WHERE 1 = 0 ifadesi hiç değer döndürmez. NULL değer yoksa sorun yok. Ama SELECT NULL from DUAL ifadesi NULL değer döndürür.

    Sorgu sonucunun NULL dönmesi için içteki sorgunun tammen NULL değer döndürmesi şart değil.Herhangi bir değerinin NULL olması yeterli.

    Mesela

    SQL>SELECT SUM (a) FROM null_test t1
          WHERE a NOT IN (SELECT 20 FROM DUAL);
    
    90
    

    a nın 20 olduğu değeri hariç bırakıp toplar. Sonuç 90

    SQL>SELECT SUM (a) FROM null_test t1
          WHERE a NOT IN (SELECT b FROM null_test);
    
    NULL
    

    b kolonuda NULL bir değer olması bu sonuca sebep oldu. Bu sorgu yerine şunu da yazabilirdik

    SQL>SELECT SUM (a) FROM null_test t1
          WHERE a NOT IN (
           SELECT 20 FROM DUAL&amp;lt;/pre&amp;gt;
    UNION ALL
           SELECT NULL FROM DUAL);
    
    NULL
    

    Bu sorgu a ‘ nın 20 ve NULL olduğu değerleri hariç bırakıp toplar mı? Hayır. Sonuç NULL.

    NULL olan değerleri filtrelersek bu sorunu çözebiliriz. Eğer NOT EXIST kullanıyorsanız join kolonlarının NULL değerlerini de dikkate almalısınız

    SQL>SELECT SUM (a) FROM null_test t1
         WHERE a NOT IN (SELECT b FROM null_test
                           WHERE b IS NOT NULL);
    
    
    

    şu sorguda b nin NULL gelen değerinden kurtulmak için sorguyu biraz çirkinleştirmemiz gerekiyor

    SQL>SELECT SUM (a) FROM null_test t1
          WHERE NOT EXISTS (SELECT b FROM null_test t2
                             WHERE t1.id=t2.id);
    
    
    
    SQL> SELECT SUM (a) FROM null_test t1
          WHERE NOT EXISTS (SELECT b FROM null_test t2
                             WHERE (t1.id = t2.id OR (t1 IS NULL AND t2 IS NULL))
    );
    
    
    &amp;lt;

    Buradaki ifadede iki tabloya join işlemi uygularken kolonlarda NULL değer olabiliyorsa dikkatli olmamız gerektiğini de söylüyor. Tabii iki tabloyu bitiştirmek için kullanacağınız kolonda NULL olması beklenmemeli.Nadir de olsa karşılaşabilceğimiz bir durum. Mesela bir SCD yapısındaki tabloyu kaynağındaki farkları ayırarak yüklüyorsanız dikkat etmeniz gerekir

    NULL içeren kolonların da join işlemine sokulacağını varsayıyorsanız sorgu yukarıdaki gibi

    SQL> SELECT * FROM a, b
          WHERE (a.id = b.id OR (a.id IS NULL AND b.id IS NULL));
    
    
    

    *Peki Dinamik SQL de NULL değeri parametre olarak kullanabilir miyiz?

    Şu ifadede 5 değeri yerine NULL koyun

    BEGIN
    EXECUTE IMMEDIATE 'UPDATE null_test SET b=:var' USING 5;
    END;
    
    BEGIN
    EXECUTE IMMEDIATE 'UPDATE null_test SET b=:var' USING NULL;
    END;
    

    hata verecektir. Peki NULL değer atamak istersek ne yapabiliriz? Bir değişkene NULL değer verebiliriz

    DECLARE
      a NUMBER;
    BEGIN
      a :=NULL;
    
      EXECUTE IMMEDIATE 'UPDATE null_test SET b=:var' USING a;
    END;
    

    Bu şekilde çalışır

    NULL değer içeren kolonlar üzerinden join ise şu şekilde yapılmalıdır.( NOT exist için kullandığımız inner sqlde kullanmıştık )

    SQL>SELECT * FROM a, b
          WHERE (a.id = b.id OR (a.id IS NULL AND b.id IS NULL));
    

    Aksi takdirde sorgu sonucunda a ve b nin NULL olduğu kayıtlar gelmez. Bunun yerine NVL(a)=NVL(b) de kullanılabilir.

    Bunların yanında sorgu sonucunu etkilemese de performansı olumsuz etkileyen bir örnek. NULL değer içeren kolonda index varsa

    Mesela null_test tablosunda a kolonunda indeks olduğunu düşünün.

    Bu tabloya çektiğiniz sorguda WHERE id IS NULL koşulu varsa indeks kullanılmaz.Perfromans kaybı yaşarsınız. İndeksi başka bir kolona koymalı ya da indeksi NVL(a, -99) gibi NULL için defult bir değer vererek oluşturmalısınız

     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Cevapla
e
Düzenle
o
Show/Hide comments
t
En üste git
l
Go to login
h
Show/Hide help
shift + esc
Vazgeç
%d blogcu bunu beğendi: