SELECT sorgusunda GROUP BY ile satırları gruplayabiliyoruz. Farklı düzeylerde raporlar oluşturmak gerektiği zaman aynı anda farklı sütunları gruplandırmanız gerekebilir. Bu işlem için UNION ALL ile sorguları birleştirmeniz gereklidir.  SQL Server 2008 ve sonraki sürümleri kullanıyorsanız GROUP BY ifadesini GROUPING SETS ile kullanarak oluşturduğunuz grupları bir araya  getirebilir ve sorgunuzun birden fazla sonuç dönmesini sağlayabilirsiniz.

GROUPING SETS ile Sorgu Yazma

GROUPING SETS, GROUP BY ifadesi kullanılan her sorgudan elde edilen sonuçları birleştirir. Yani bu işleme UNION ALL’un bir alternatifidir de diyebiliriz.

GROUPING SETS ile sütun kombinasyonlarını gruplayabilirsiniz:

SELECT <sütun listesi>
FROM <source>
GROUP BY
GROUPING SETS(
 (<column_name>),--bir veya daha fazla sütun
 (<column_name>),--bir veya daha fazla sütun
 () -- tüm satırların aggregate edilmesini belirtir
 ); 

GROUPING SETS ile gruplandırılacak nesneleri ve bunların sırasını kendiniz belirlersiniz. Herhangi bir kombinasyonda gruplandırma yapmak isterseniz sonraki bölümlerde ele alacağımız CUBE ve ROLLUP konusuna göz atabilirsiniz.

Bu sorguda GROUPING SETS kullanarak Category ve Cust sütunlarında ve boş parantez kullanarak tüm satırlarda aggregate gerçekleştirilmiştir:

Code Example Content
SELECT Category, Cust, SUM(Qty) AS TotalQty
FROM Sales.CategorySales
GROUP BY
 GROUPING SETS((Category),(Cust),())
ORDER BY Category, Cust; 

Sonuç:

Category Cust TotalQty
----------- ---- --------
NULL NULL 999
NULL 1 80
NULL 2 12
NULL 3 154
NULL 4 241
NULL 5 512
Beverages NULL 513
Condiments NULL 114
Confections NULL 372

Tabloda NULL değerler olduğunu görüyoruz, sebebi işlenen veriler içerisinde null değer olmasından ya da sadece yer tutucu olarak atandığından olabilir. ilk satırda “NULL, NULL, 999” görüyorsunuz, bu bir satırın genel toplamının temsili ifadesidir. Category ve Cust sütunlarındaki NULL değerlerin sadece yer tutucu işlevi vardır, bu iki sütunda aggregation gerçekleştirilmemiştir.

CUBE ve ROLLUP

GROUPING SETS gibi CUBE ve ROLLUP operatörleri de aggregation için veriler üzerinde birden fazla gruplama işlemi gerçekleştirir. Ancak bu ifadelerde sütun gruparını teker teker yazmanıza gerek yoktur. CUBE operatörüne sütunları verdiğinizde tüm olası kombinasyonları ve output gruplarını otomatik olarak belirleyecektir. ROLLUP ifadesi ise kombinasyonları, sütunları belli bir hiyerarşide olduğunu varsayarak oluşturur. Bu nedenle CUBE ve ROLLUP operatörlerini GROUPING SETS işleminin kısayolu olarak düşünülebilirsiniz.

CUBE işlevini kullanmak için GROUP BY ifadesine CUBE anahtar sözcüğü eklemeniz yeterli. Gruplanacak sütunları da belirtmeyi unutmayın. ROLLUP kullanımı da aynen bu şekildedir.

Bu sorguda Category ve Cust sütunlarını tüm kombinasyonlarda gruplandırdık:

SELECT Category, Cust, SUM(Qty) AS TotalQty
FROM Sales.CategorySales
GROUP BY CUBE(Category,Cust); 

Burada (Category, Cust), (Cust, Category), (Cust), (Category) ve tüm boş () kombinasyonlar gruplandırılmış oldu.

Aşağıdaki sorguda ise ise ROLLUP kullanılarak Category, Subcategory ve Product sütun kombinasyonlarını gruplandırdık:

SELECT Category, Subcategory, Product, SUM(Qty) AS TotalQty
FROM Sales.ProductSales
GROUP BY ROLLUP(Category,Subcategory, Product); 

Burada (Category, Subcategory, Product), (Category, Subcategory), (Category) ve tüm boş () kombinasyonlar gruplandırıldı. Sütunların verildiği sıralama burada önemli, çünkü işlem yapılırken sütun sırasının bir hiyerarşide olduğu varsayılır.

GROUPING_ID

Görüldüğü üzere birden çok grup kümesiyle aynı sorguda farklı aggregate işlemlerini gerçekleştirebiliyoruz. Ayrıca, bir satır herhangi bir grupta yer almazsa SQL Server buraları boş bırakmamak için NULL ile doldurur. Peki birden fazla kümeyi işleyen bir sorguda NULL değerin yer tutucu olarak atandığını veya bunların işlenen verilerden gelip gelmediğini nasıl anlarız? Gruplandırılmış veriler içerisinde NULL değer varsa, bu değer hangi küme için kullanılmış? Tarzındaki sorulara GROUPING_ID ile bunlara yanıt bulabiliriz.

Aşağıda çok sayıda NULL değer içeren sorguya bir göz atalım:

SELECT Category, Cust, SUM(Qty) AS TotalQty
FROM Sales.CategorySales
GROUP BY
GROUPING SETS((Category),(Cust),())
ORDER BY Category, Cust; 

Dönen sonuç:

Category Cust TotalQty
--------------- ----------- --------
NULL NULL 999
NULL 1 80
NULL 2 12
NULL 3 154
NULL 4 241
NULL 5 512
Beverages NULL 513
Condiments NULL 114
Confections NULL 372 

İlk başta sütunda neden NULL ifadesinin olduğunu anlamak zor olabilir.

Sonuç satırlarıyla grupları ilişkilendirmek için GROUPING_ID’yi kullanabilirsiniz:

SELECT
 GROUPING_ID(Category)AS grpCat,
 GROUPING_ID(Cust) AS grpCust,
 Category, Cust, SUM(Qty) AS TotalQty
FROM Sales.CategorySales
GROUP BY CUBE(Category,Cust); 

Dönen sonuç:

grpCat grpCust Category Cust TotalQty
----------- ----------- --------------- ----------- -----------
0 0 Beverages 1 36
0 0 Condiments 1 44
1 0 NULL 1 80
0 0 Beverages 2 5
0 0 Confections 2 7
1 0 NULL 2 12
0 0 Beverages 3 105
0 0 Condiments 3 4
0 0 Confections 3 45
1 0 NULL 3 154
...
1 1 NULL NULL 999
0 1 Beverages NULL 513
0 1 Condiments NULL 114
0 1 Confections NULL 372

Görüldüğü gibi GROUPING_ID işlevi, belirlenen satır gruplandırılmış verilerin bir parçasıysa 1 değerini değilse 0 değerini döndürür. İlk satırda hem grpCat hem de grpCust ikisi de 0 değerini döndürür; bu nedenle ilk satırın (Category, Customer) kombinasyonunun bir parçası olduğu anlaşılabilmektedir.

GROUPING_ID işlevine input olarak birden çok sütun verebilirsiniz. Fonksiyon her grup kümesi için bir bitmap döndürecektir.

Sonraki yazıda görüşmek üzere. 

Kaynak:
Using GROUP BY with ROLLUP, CUBE, and GROUPING SETS
GROUPING (Transact-SQL)
GROUPING_ID (Transact-SQL)