Son Haberler
Anasayfa / Yazılım / SQL / Toplama Fonksiyonlarının GROUP BY İle Birlikte Kullanımı

Toplama Fonksiyonlarının GROUP BY İle Birlikte Kullanımı

Bu yazımda aggregate (toplama) fonksiyonlar ile birlikte GROUP BY deyiminin kullamına değinmek istiyorum. Toplama fonksiyonları bir veri seti üzerinde en son istediğimiz fonksiyonun özelliğine göre sonucu vermektedir. Biz sorgularımızda bazı alanların yani bazı kolonların toplama fonksiyonları işlemine tabi tutulmasını istemeyiz. İşte bu gibi durumlarda gruplandırma yapmamız gerekmektedir. Bunun içinde GROUP BY deyimine ihtiyaç duyarız.

Örneğin bir veritabanında yer alan tabloda siparişlerin toplamını ve siparişlerin sayısını sipariş tarihine ya da müşteriye göre listelemek isteyebiliriz. Bu gibi durumlarda gruplama yapmamız gerekir. Bunun için syntax (söz dizimi) aşağıdaki gibidir:

SELECT ToplamaFonksiyonu(kolon1), kolon2 FROM tablo GROUP BY kolon2

Görüldüğü üzere hem toplama fonksiyonu uygulanacak kolonu hem de toplama fonksiyonu uygulanmayacak kolonu aynı SELECT sorgusu içinde kullanabiliyorum bunu yapabilmek için GROUP BY deyimi ile gruplama yapıyorum. Burada eğer toplama fonskiyonu uygulamayacağım kolon ne kadar ise o kadarını GROUP BY ile ifade etmem gerekiyor.

Şimdi öncelikle GROUP BY kullanmadan bir örnek yapalım ve ne gibi bir hata mesajı alıyoruz görelim, daha sonra doğru olan sorgumuzu yazarız. AdventureWorks2012 veri tabanı üzerinde çalışıyorum.

SELECT CustomerID, SUM(TotalDue) AS "Müşteri Başına Toplam" FROM Sales.SalesOrderHeader

Sorguda Sales.SalesOrderHeader tablosundan CustomerID alanını ve TotalDue alanının toplamını listeliyorum ancak hem toplama fonksiyonu olan TotalDue alanı var hemde her satırın listelenmesi gereken CustomerID var dolayısı ile hata alırım.

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

Bu hatadan kurtulmak için GROUP BY ile toplama fonksiyonuna tabi tutmadığım kolonu grupluyorum, böylece hatadan kurtuluyorum.

SELECT CustomerID, SUM(TotalDue) AS "Müşteri Başına Toplam"
FROM Sales.SalesOrderHeader GROUP BY CustomerID

Böylelikle her ortak CustomerID birleşiyor ve o birleşen verilerin toplam TotalDue’e göre toplamını listeliyorum.

2013031423

Bir örnek daha yapalım.

SELECT TerritoryID, AVG(TotalDue) AS "Bölge Başına Ortalama"
FROM Sales.SalesOrderHeader GROUP BY TerritoryID

Bu sefer Sales.SalesOrderHeader tablosundan TerritoryID ve TotalDue alanının ortalamasını listeleyeceğim. Gruplamayı da toplama fonksiyonu olmayan TerritoryID üzerinden yapıyorum.

2013031424

Birde diyelim ki siz hem toplama fonksiyonu kullanıyorsunuz hemde farklı fonksiyonlar ile bir başka kolonuda nitelendirmek istiyorsunuz. Örneğin, YEAR fonksiyonu gibi. Şimdi iki ayrı sorgu ile ben bunu açıklayayım.

SELECT COUNT(*) AS "Siparişlerin Sayısı", YEAR(OrderDate) AS "Sipariş Yılı"
FROM Sales.SalesOrderHeader GROUP BY OrderDate

Sonuca bakalım :

2013031425

Şimdi sonuç ekranında görüleceği üzere Sipariş Yılı sütununda yıllar birden fazla. Oysaki benim yapmak istediğim yılları bir defa göstersin ve her yılki toplam siparişlerin sayısını bulsun. O halde benim şu an üstteki sorgumda şunu demek istedim:

Tüm satırlar üzerinde işlem yap bunların sayısını al ancak OrderDate alanını YEAR bilgisini al dedim. Normalde bu ORDERDATE alanı yıl gün ve ay bilgisinden oluşuyor. Buradaki YEAR ifadesi sadece bu tarih bilgisinin YEAR yani yıl bilgisini almak için kullanılıyor. Dolayısı ile ben eğer yıllara göre gruplama yapacak isem sadece GROUP BY OrderDate demem yeterli değil. O halde sorgum nasıl olmalı? Sorgumun doğru şekli aşağıdaki gibidir :

SELECT COUNT(*) AS "Siparişlerin Sayısı", YEAR(OrderDate) AS "Sipariş Yılı"
FROM Sales.SalesOrderHeader GROUP BY YEAR(OrderDate)

Sonuç :

2013031426

Görüldüğü üzere bu sefer yıllara göre siparişlerin sayısını listeledik. Örneklere devam edelim.

1) Sales.SalesOrderDetail tablosunda sipariş edilen her ürünün kaçar tane sipariş edildiğini listeleyelim.

SELECT ProductID, SUM(OrderQty) AS "Sipariş Edilen Ürün Sayısı" 
FROM Sales.SalesOrderDetail GROUP BY ProductID

2013031427

2) Sales.SalesOrderDetail tablosundan SalesOrderID’ye göre siparişlerin sayısını listeleyelim.

SELECT SalesOrderID, COUNT(*) AS "Sipariş Sayısı" 
FROM Sales.SalesOrderDetail GROUP BY SalesOrderID

2013031428

3) Production.Product tablosunda ProductLine kolonunu kullanarak her bir ürünün sayısını listeleyelim.

SELECT ProductLine, COUNT(*) AS "Ürün Sayısı"
FROM Production.Product GROUP BY ProductLine

2013031429

4) Sales.SalesOrderHeader tablosundaki her müşteri için yılı baz alınarak sipariş edilen ürünlerin sayısını listeyelim.

SELECT CustomerID, COUNT(*) AS "Satış Sayısı", YEAR(OrderDate) AS "Sipariş Yılı"
FROM Sales.SalesOrderHeader GROUP BY CustomerID, YEAR(OrderDate)

2013031430

2 yorum

  1. Hocam sayac tablomda 3 adet sütun var.
    Tarih(datetime), IPno(nvarchar(50), Toplam(int) şeklinde. Sayac şu şekilde çalışıyor. Gelen IpNo yoksa yeni satır ekliyor varsa Ilgili Ip adresinin karşısında Toplam sütununa +1 ekliyorum.
    Kayıtları listelerken günlük tekil, günlük çoğul, dün tekil, dün çoğul şeklinde sqlden veriyi çekip labellere aktarabiliyorum. Ancak tarihleri süzüp en çok tekil giriş yapılan tarihte count sayısını alamıyorum. Yardımcı olabilir misiniz?
    Not: Tabloyu ilk oluşturduğumda tarih (date) idi. İlk kayıtlar ör: 2016/08/15 00:00:00 şeklinde geliyordu. Bu kayıtlarda
    — select top 1 tarih = convert(varchar(20),Tarih,106) , count(Toplam) grupla
    –from Sayac
    –group by tarih
    –order by grupla desc
    Stored Procedures ile kaydı çekebiliyorum.
    Ancak sütun tipi datetime ile kayıt satır toplamını alamıyorum.

  2. İsmail hocam süpersin, günlük satış, günlük alış, günlük hareket tablosu yapmam gerekiyordu. Sayende bir adım yaklaştım. Aradığımda sürekli karşıma group by ın en kolayı kullanılıyordu. Amacım 21.08.2016 tarihinde şu kadar alım yapıldı, bu kadar satış yapıldı, bu kadar kâr elde edildi. Şeklinde tablo olarak gridview de sunmaktı seçilen iki tarih arasında. Ancak bir türlü istediğim gibi olmadı. Siz YEAR fonksiyonunu kullanmışsınız, ben DAY olarak değiştirdim. Ama bana Gün ay yıl lazım bu konuda yardımcı olur musunuz?

Bir cevap yazın

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