Aggregate fonksiyonlarını kullanmadan önce verileri altkümeler şeklinde düzenlemek isteyebilirsiniz. Bu bölümde, GROUP BY ifadesini kullanarak altkümeleri nasıl oluşturabileceğimizi göreceğiz.

GROUP BY Kullanımı

Daha önce gördüğümüz üzere, SELECT ifadesinde FROM ve WHERE işlemleri gerçekleştiktek sonra sonra sanal bir tablo oluşturulur. Sanal tablonun daha sonraki işlemler için kullanılabilir. GROUP BY ifadesini kullanarak, önceki sorgu aşamalarının sonuçlarını satır gruplarına ayırabiliriz.

GROUP BY ifadesiyle gruplandırmak istediğiniz bir veya daha fazla öğeyi ifade tanımında belirtmeniz gerekir:

GROUP BY <value1> [, <value2>, …] 

GROUP BY, gruplar oluşturur ve ifadede belirtilen öğelerin benzersiz kombinasyonlarıyla belirlenen satırları oluşturulan her gruba yerleştirir.

Örneğin aşağıdaki sorguda, Sales.Orders tablosunda empid başına bir tane olmak üzere gruplandırılmış satırları getirecektir:

FROM SalesOrders
GROUP BY empid; 

GROUP BY ifadesiyle satırlar bir grupla ilişkilendirildikten sonra, sorgunun sonraki aşamalarında GROUP BY listesinde görünmeyen satırların tüm öğeleri kümelenmelidir. SELECT ve HAVING ifadelerini yazarken bu dikkate alarak yazarsınız.

Bu sorguda benzersiz çalışan kimliğine bağlı 830 kaydın dokuz gruba ayrıldığı gösterilmektedir:

SELECT empid, COUNT(*) AS cnt
FROM Sales.Orders
GROUP BY empid; 

Dönen sonuç:

empid cnt
----- -----
1 123
2 96
3 127
4 156
5 42
6 67
7 72
8 104
9 43
(9 row(s) affected) 
Mantıksal İşlem Sırasında GROUP BY

GROUP BY kullanırken bir takım zorluklar da karşımıza çıkacaktır. Aşağıdaki hata mesajını iyi anlamanız gereklidir:

Msg 8120, Level 16, State 1, Line 2 
Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. 

Sorgu çalışması sırasında mantıksal işlem sırasına göz atılması bu sorunu açıklığa kavuşturmada bize yardımcı olacak.

Daha önce belirtildiği gibi, SELECT ifadesi FROM, WHERE, GROUP BY ve HAVING tümceleri işlenene kadar işlenmez. GROUP BY, SELECT ifadesinden daha önce işlenirken aynı zamanda FROM ve WHERE deyimlerinden gelen sonuçları da kendi sonuçlarıyla değiştirmektedir. Sorgu sonucunda, her bir grup için yalnızca bir satır dönecektir (HAVING varsa). Bu nedenle, SELECT, HAVING ve ORDER BY dahil GROUP BY’dan sonra gerçekleştirilen tüm işlemler, orijinal satırlarda değil gruplarda gerçekleştirilir. Örneğin, SELECT listesindeki sütunlar, her grup başına skaler değer döndürmelidir. Bu işlemler, gruplandırılan sütun veya üzerinde gerçekleştirilen aggregate fonksiyonu olabilir.

SELECT listesindeki her bir sütun, ya GROUP BY ifadesindeki bir sütun ya da her grup üzerinde işlem yapan aggregate fonksiyonu olduğundan aşağıdaki sorgu düzgün çalışacaktır:

SELECT empid, COUNT(*) AS cnt
FROM Sales.Orders
GROUP BY empid; 

Dönen sonuç:

empid count
----- -----
1 123
2 96
3 127
4 156
5 42
6 67
7 72
8 104
9 43 

Aşağıdaki sorguda, orderdate bir GROUP BY girdisi olmadığından ve bu sütunun verileri FROM ifadesinden sonra kaybolduğundan hata dönecektir:

SELECT empid, orderdate, COUNT(*) AS cnt
FROM Sales.Orders
GROUP BY empid; 

Dönen sonuç:

Msg 8120, Level 16, State 1, Line 1 
Column 'Sales.Orders.orderdate' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. 

empid ve orderyear sütununa göre gruplandırılmış siparişleri görmek için bu sütun isimleri GROUP BY ifadesiyle aşağıdaki şekilde kullanılmalıdır:

SELECT empid, YEAR(orderdate) AS orderyear, COUNT(*) AS cnt
FROM Sales.Orders
GROUP BY empid, YEAR(orderdate)
ORDER BY empid, YEAR(orderdate); 

Dönen sonuç:

empid orderyear count
----- --------- -----
1 2006 26
1 2007 55
1 2008 42
2 2006 16
2 2007 41 
GROUP BY İşlem Akışı

İlk önce WHERE deyimi ve ardından GROUP BY deyimi işlenmektedir.

SELECT SalesOrderID, SalesPersonID,
CustomerID
FROM Sales.SalesOrderHeader;

SELECT SalesOrderID, SalesPersonID, CustomerID
FROM Sales.SalesOrderHeader
WHERE CustomerID IN (29777, 30010);

SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE CustomerID IN (29777, 30010)
GROUP BY SalesPersonID; 
Aggregate Fonksiyonlarında GROUP BY Kullanımı

Belirtildiği üzere, bir T-SQL sorgusunda GROUP BY ifadesi kullanılıyorsa SELECT ifadesinde listelenen tüm sütunların ya GROUP BY tarafından kullanılması ya da gruplar üzerinde işlem yapan aggregate fonksiyonlarına input olması gerekir.

COUNT fonksiyonunun GROUP BY ile birlikte sorgularda kullanıldığını görmüştük. Aşağıdaki örnekte, her ürün başına en büyük sipariş miktarını görüntülemek için MAX fonksiyonu kullanılmıştır:

SELECT productid, MAX(qty) AS largest_order
FROM Sales.OrderDetails
GROUP BY productid; 

Dönen sonuç:

productid largest_order
----------- -------------
23 70
46 60
69 65
29 80
75 120 

Not: MAX fonksiyonunda input olarak kullanılan qty sütunu, GROUP BY ifadesinde kullanılmaz. FROM … WHERE aşaması tarafından döndürülen satırları GROUP BY aşamasına gelince kaybolmasına rağmen, sütunlar aggregation işlemleri için hâlâ kullanılabilir.

Kaynak:
SELECT – GROUP BY – Transact-SQL
Troubleshooting GROUP BY Errors