SQL Server eski sürümlerinden beri GROUP BY ile veri özetlemesini destekler ayrıca ara ve alt toplamlar için WITH ROLLUP ve WITH CUBE yantümcelerini sunar. SQL Server 2008, konuyla ilgili GROUPING SETS isimli yeni bir operatör sunmaktadır. Bu makalede bu konudaki değişiklikleri örneklendireceğiz. GROUP BY, WITH ROLLUP ve WITH CUBE yantümceleriyle ilgili detayı aşağıdaki makalemde bulabilirsiniz.
SQL’de veri özetleme ve gizli “OLAP raporlama”
Örnek olarak aşağıdaki içeriğe sahip Satis tablomuz olduğunu düşünelim.
Bu tabloda Lokasyon, Ay ve Kategori olmak üzere boyut olarak kullanabileceğimiz 3 alan bulunmaktadır. Ayrıca KPI / Sayısal Gösterge olarak Tutar kolonunu kullanacağız. Amacımız aşağıdaki gibi her boyut’un toplamını aynı anda görebilmek olsun.
Sonuçta görüleceği gibi Ay ve Lokasyon verilerininin toplamını aynı listede görünmektedir. SQL’de bunu yapabilmek için her alanı gruplayıp UNION ile birleştirmek gerekir.
SELECT '' AS Lokasyon, Ay, SUM(Tutar) Ciro FROM Satis GROUP BY Ay UNION ALL SELECT Lokasyon, '' Ay, SUM(Tutar) Ciro FROM Satis GROUP BY Lokasyon
Bu şekilde birden fazla boyutu işin içine katmak istediğimizde her biri için UNION serisi oluşturmalıyız. SQL Server 2008 ile birlikte gelen GROUPING SETS tümcesi hem esneklik hem de performans sunmaktadır. ANSI SQL 2006 ile uyumlu bu tümceyi GROUP BY ile birlikte kullanılan bir fonksiyon gibi düşünebiliriz. Parametre olarak hangi boyutlar için özetleme yapılacaksa onları yazmamız yeterli olacaktır.
SELECT Lokasyon, Ay, SUM(Tutar) Ciro FROM Satis GROUP BY GROUPING SETS ( Lokasyon, Ay )
Veya örneğimizdeki görüntünün aynısını almak için NULL değerlerini replace edecek şekilde düzenleme yapalım.
SELECT ISNULL(Lokasyon,''), ISNULL(Ay,''), SUM(Tutar) Ciro FROM Satis GROUP BY GROUPING SETS ( Lokasyon, Ay )
Örneğimizdeki üç boyutu kullanarak bütün ihtimalleri yazdıracak olursak SQL Server 2008 öncesi ve sonrasını aşağıdaki gibi yazabiliriz.
SELECT NULL AS Lokasyon, Ay, Kategori, SUM(Tutar) Ciro FROM Satis GROUP BY Ay,Kategori UNION ALL SELECT Lokasyon, NULL Ay, Kategori, SUM(Tutar) Ciro FROM Satis GROUP BY Lokasyon,Kategori UNION ALL SELECT Lokasyon, Ay, NULL Kategori, SUM(Tutar) Ciro FROM Satis GROUP BY Lokasyon,Ay
Bu ifadeyi GROUPING SETS içerisinde yazarken yine aynı şekilde sırasıyla hangi alanları gruplamışsak onları yazmamız yeterli olacaktır.
SELECT Lokasyon, Ay, Kategori, SUM(Tutar) Ciro FROM Satis GROUP BY GROUPING SETS ( (Ay, Kategori), (Lokasyon, Kategori), (Lokasyon, Ay) )
Lokasyon ve Ay boyutlarını kullanarak “Ara Toplam” ve “Alt Toplam” alacağımız şekilde özetleme yapalım.
SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY Lokasyon, Ay UNION SELECT Lokasyon, NULL, SUM(Tutar) Tutar FROM Satis GROUP BY Lokasyon UNION SELECT NULL, NULL, SUM(Tutar) Tutar FROM Satis
Daha anlaşılır olması için sıralama yapalım.
SELECT * FROM ( SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY Lokasyon, Ay UNION SELECT Lokasyon, NULL, SUM(Tutar) Tutar FROM Satis GROUP BY Lokasyon UNION SELECT NULL, NULL, SUM(Tutar) Tutar FROM Satis ) as T ORDER BY ISNULL(Lokasyon,'ZZZZ'), ISNULL(Ay,'ZZZZ')
Tabi bu tür özetleme işlemlerini bu şekilde her boyut için UNION ile birleştirmek yerine WITH ROLLUP veya WITH CUBE ile yapıyoruz. Böylece daha kolay bir yazımla aynı sonucu elde etmiş olacağız.
SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY Lokasyon, Ay WITH ROLLUP
GROUPING SETS ile aynı sonucu elde etmek için özetleme yapılacak alan veya alanları yazmamız yeterli olacaktır.
SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( (Lokasyon, Ay), --Lokasyon, Ay kırılımlı Lokasyon,--Sadece lokasyon kırılımlı ()--Kırılımsız (grand total) )
Görüldüğü gibi GROUPING SETS yönteminde esneklik bulunmaktadır. WITH ROLLUP otomatik olarak gruplanmış tüm alanlara ait toplam satırı oluştururken GROUPING SETS hangileri için tanımlama yapmışsak onları oluşturmaktadır. Örneğin “Alt Toplam” istenmiyorsa GROUPING SETS içerisindeki “()-Kırılımsız” satırını kaldırmamız yeterli olacaktır.
--Alt Toplam Olmasin SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( (Lokasyon, Ay), Lokasyon ) --Ara Toplam Olmasin SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( (Lokasyon, Ay) ) --Sadece Alt Toplam Olsun SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( (Lokasyon, Ay), () )
“Ay” alanı için de özetleme yapabilmesi için GROUPING SETS içerisine Ay eklenir. Böylece Lokasyo ve Ay alanları için tüm muhtemel özetleme satırları oluşmuş olacaktır. Bunu da bilindiğim WITH CUBE ile yapıyorduk.
--WITH CUBE yöntemi SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY Lokasyon, Ay WITH CUBE --GROUPING SETS yöntemi SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( (Lokasyon, Ay), Lokasyon, Ay, () )
GROUPING SETS içerisinde kullanılan boyutların kullanım sırası önemli değildir. Hep aynı sonucu döndürür.
Örneğimizdeki 3 alanı da alt toplam almadan ekleyelim.
SELECT Lokasyon, Ay, Kategori, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( (Lokasyon, Ay, Kategori), (Lokasyon, Ay), Lokasyon, Ay )
GROUPING SETS’in sunduğu kolaylıklardan biri de ara toplamların sadece belli kolonlar için oluşturulabileceğinin belirtilebiliyor olmasıdır. Önceki örneğimiz tüm özetleme grupları için ara toplam satırı oluşturuldu. Oysa lokasyonu sabitleyip sadece Ay ve Kategori için ara toplam oluşturabiliriz.
SELECT Lokasyon, Ay, Kategori, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( Lokasyon, ROLLUP(Ay, Kategori) )
SELECT Lokasyon, Ay, Kategori, SUM(Tutar) Tutar FROM Satis GROUP BY GROUPING SETS ( Lokasyon, Kategori, ROLLUP(Ay) )
Sonuç olarak SQL Server 2008 ile birlikte WITH ROLLUP veya WITH CUBE ifadeleri yerine bunu doğrudan GROUPING SETS ile yapmak tavsiye edilir. Eski tümceler desteklenmekle birlikte bu ifadeler aşağıdaki gibi doğrudan GROUP BY ile birlikte kullanılabilir.
SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY ROLLUP (Lokasyon, Ay) SELECT Lokasyon, Ay, SUM(Tutar) Tutar FROM Satis GROUP BY Lokasyon, ROLLUP (Ay)
GROUPING_ID() fonksiyonu
SQL Server 2008 ile birlikte gelen konuyla ilgili diğer fonksiyon GROUPING_ID() fonksiyonudur. Bu fonksiyon parametre olarak aldığı alanların özetleme seviyesini belirtir. MSDN’den alınmış aşağıdaki tablo bu fonksiyonun çalışma şeklini çok güzel anlatmaktadır. a, b ve c olmak üzere 3 kolonun bulunduğunu düşünelim.
Özetlenmiş Alanlar | GROUPING_ID(a,b,c)=GROUPING(a)+GROUPING(b)+GROUPING(c) | GROUPING_ID() |
---|---|---|
a | 100 | 4 |
b | 010 | 2 |
c | 001 | 1 |
ab | 110 | 6 |
ac | 101 | 5 |
bc | 011 | 3 |
abc | 111 | 7 |
Aşağıdaki ifadenin açılımı yan tarafta gösterilmiştir;
SELECT GROUPING_ID(A,B) FROM T GROUP BY CUBE(A,B) |
SELECT 3 FROM T GROUP BY () UNION ALL SELECT 1 FROM T GROUP BY A UNION ALL SELECT 2 FROM T GROUP BY B UNION ALL SELECT 0 FROM T GROUP BY A,B |
Merhabalar Ahmet bey, Gruplama yaparak toplamaya çalıştığımda aşağıdaki hatayı alıyorum. SQL versiyonum da 2012 ancak bu hatayı alıyorum. İnternette araştırmama rağmen bir sonuca ulaşamadım. Belki sizin bir bilginiz vardır.
The CUBE() and ROLLUP() grouping constructs are not allowed in the current compatibility mode. They are only allowed in 100 mode or higher.
Mert Bey merhaba,
Kullandığınız sunucu SQL Server 2012 olsa da compatibility_level değeri önemli. Aşağıdaki sorgunun sonucunda hangi rakam geliyor. 100’dan büyük rakam gelmesi lazım.
SELECT compatibility_level FROM sys.databases
Eğer gelmiyorsa Database’i sağ yıklayıp Properties bölümünden seçilebiliyorsa son sürümü seçin. Bu arada SQL Server 2012 olduğundan da emin olmanız gerekiyor. Bunun için de aşağıdaki sorguyu çalıştırabilirsiniz.
SELECT @@VERSION
Geri izleme: SQL Aggregate Functions – Toplam Fonksiyonları – Mustafa BÜKÜLMEZ
Geri izleme: SQL Aggregate Functions – Toplam Fonksiyonları – Mustafa BÜKÜLMEZ