13 Nisan 2018 Cuma

sql ile taklalar - partition by (row_number) kullanımı

      Merhabalar. 

      Kaç zamandır ortadoğu ve balkanların en tembel yazılımcısı olarak bloğumun adını tembel-programci olarak değiştirmeyi düşünüyorum ama çok üşeniyorum:) Neyse 2 buçuk yıllık İstanbul gezmelerinde yapıp geldikten sonra biz İzmir yazısı yazayım dedim. İstanbul'daki iş hayatımda türlü türlü sql sorgu taklaları attıktan sonra olaya sql yazısı ile geri döneyim dedim. sql sorguları yazarken guruplama ve gurup içindeki en küçük yada en büyük elemanı bulmak çok sık kullandığımız bir işlem. Bu işlemi genelde group by ile çözüyoruz ama bazen gurup içindeki en büyük değeri almak yetmiyor en büyük yada en küçük değerin olduğu tüm satırı almak gerekebiliyor. 

      Mesela veritabanındaki tüm müşterilerin son alışverişlerinin tutarlarını listelemek gibi. Bu gibi durumlarda imdadımıza partition by ifadesi yetişiyor. Konuyu daha anlaşılır kılmak için basit bir örnek yapmak iyi olur sanırım. Bu arada elimin altında hazır olduğu için örnekleri MS Sql Server üzerinde yazacağım. Diğer sql sunucuları içinde sorgular çok farklı değil. 

    SELECT musteri_adi, musteri_no, fatura_tarih, fatura_toplam 
    FROM (
        SELECT m.musteri_adi, m.musteri_no, f.fatura_tarih, f.fatura_toplam, 
            ROW_NUMBER() OVER(PARTITION BY m.musteri_id ORDER BY f.fatura_tarihi DESC) rn 
        FROM fatura f
            INNER JOIN musteri m ON f.musteri_id = m.musteri_id
        WHERE fatura_iptal = 0
    ) fl

    WHERE fl.rn = 1

      Örneği kısaca anlatarak anlamayı kolaylaştırayım. içerideki sorguda müşterilerin tüm faturaları listeleniyor. partition by ile sorgu sonucu musteri_id alanındaki degerlere göre parçalanıyor ve fatura_tarihi alanına göre ters sıra ile her satır rn alanında numaralandırılıyor. Yani her müşteri için sıra 1'den başlayarak her faturası için ilerliyor. Dıştaki sorguda rn = 1 şartı ile her müşteri faturası için sadece ilk kaydın seçilmesi sağlanıyor. 

     Aslında bugün farklı bir konu anlatmayı düşünüyordum. Bu hafta içinde iş yerinde önemli bir sorunu cursor kullanmak yerine dense_rank ile çok harika bir şekilde çözmüş ve bununla ilgili bir örnek anlatacaktım ama konuyu geriden alınca saat geç oldu. Artık yarın yada bir kaç yıl sonra onuda yazarım...

Hiç yorum yok:

Yorum Gönder