SQL Server 2008 GROUP BY GROUPING SETS GROUPING_ID ROLLUP CUBE

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ş AlanlarGROUPING_ID(a,b,c)=GROUPING(a)+GROUPING(b)+GROUPING(c)GROUPING_ID()
a1004
b0102
c0011
ab1106
ac1015
bc0113
abc1117

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

SQL Server 2008 GROUP BY GROUPING SETS GROUPING_ID ROLLUP CUBE” üzerine 2 düşünce

  1. mert bozkurt

    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.

    Cevapla
  2. Ahmet Kaymaz Yazar

    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

    Cevapla

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Time limit is exhausted. Please reload CAPTCHA.