1. Toplam Analiz Girişi

Toplama işlemi, veritabanı sorgularında çok önemli bir kavramdır. Genellikle toplama, sayma, ortalama, maksimum ve minimum değerler gibi istatistiksel analizler için kullanılır. Bu işlemler, kullanıcılara büyük miktarda veriden anlamlı bilgiler çıkarmalarına yardımcı olarak veri analizi ve karar verme desteği sağlar. Veritabanında toplama için uygulanan işlevler genellikle toplama işlevleri olarak adlandırılır.

2. Temel Toplama İşlemleri

2.1. Toplama İşlevlerinin Kavramı

Toplama işlevleri, veritabanı sorgu dillerinde kullanılan ve bir dizi hesaplama gerçekleştiren ve tek bir değer döndüren işlevlerdir. SQL ve benzeri sorgu dillerinde, toplama işlevleri veri sütunu üzerinde işlem yapabilir ve toplam (SUM), ortalama (AVG), sayma (COUNT), maksimum (MAX) ve minimum (MIN) gibi tek bir değer döndürebilir. Veri istatistiksel analizi gerçekleştirmemiz gerektiğinde, toplama işlevleri veri kümelerini işlemek ve istatistiksel veri çıkarmak için önemli araçlardır.

2.2. Tek-Alanlı Toplama

Pratik uygulamalarda, tek-alanlı toplama analizi çok yaygın bir gereksinimdir ve genellikle belirli bir sütunun toplamı, ortalaması, maksimum ve minimum değerleri gibi istatistiksel sonuçları elde etmek için kullanılır. Diyelim ki ödeme bilgisi tablomuz var ve kullanıcıların ödediği toplam tutarı hesaplamak istiyoruz. ent çatısı kullanarak, varlıktan sorgu oluşturabilir ve toplama işlevlerini aşağıdaki gibi uygulayabiliriz:

func Yap(ctx context.Context, client *ent.Client) {
    // Ödeme varlığı için Miktar alanının toplamını hesapla
    toplam, err := client.Payment.Query().
        Aggregate(
            ent.Sum(payment.Amount),
        ).
        Int(ctx)
    if err != nil {
        log.Fatalf("Toplam alınamadı: %v", err)
    }
    log.Printf("Ödemelerin toplam tutarı: %d", toplam)
}

Yukarıdaki kod örneğinde, client.Payment.Query() kullanarak ödeme varlığı için bir sorgu başlatırız, ardından Aggregate() yöntemini kullanarak parametre olarak payment.Amount ile ent.Sum işlevini çağırarak ödemelerin toplam tutarını hesaplarız. Sonra sonucu bir tamsayıya dönüştürmek için .Int(ctx) kullanır ve kaydederiz.

2.3. Çok-Alanlı Toplama

Birçok durumda, sadece bir alanda değil, birden çok alanda toplama işlemleri gerçekleştirmemiz gerekebilir. Bu bölümde, bir örnek üzerinden çok-alanlı toplamayı nasıl gerçekleştireceğimizi göstereceğiz.

Bu örnekte, evcil hayvan tablosundaki Yaş alanının toplamını bulup, minimumunu, maksimumunu ve sayısını bulacağız.

func Yap(ctx context.Context, client *ent.Client) {
    var v []struct {
        Toplam, Min, Max, Sayı int
    }
    err := client.Pet.Query().
        Aggregate(
            ent.Sum(pet.FieldAge), // Yaşın toplamı
            ent.Min(pet.FieldAge), // Minimum Yaş
            ent.Max(pet.FieldAge), // Maksimum Yaş
            ent.Count(),           // Sayma
        ).
        Scan(ctx, &v)
    if err != nil {
        log.Fatalf("Sorgu başarısız: %v", err)
    }
    // Tüm toplama sonuçlarını çıktıla
    for _, toplam := range v {
        fmt.Printf("Toplam: %d Min: %d Max: %d Sayı: %d\n", toplam.Toplam, toplam.Min, toplam.Max, toplam.Sayı)
    }
}

Yukarıdaki kodda, çok-alanlı toplama işlemi için Aggregate işlevini kullanır ve sonuçları v dilimine kaydetmek için Scan işlevini kullanırız. Sonra, v üzerinde dolaşarak tüm toplama sonuçlarını çıktılarız.

3. Gruplandırma Toplama Uygulaması

3.1. Alanları Gruplamak İçin Group By Kullanımı

Veritabanı işlemlerinde, Group By, verileri gruplamak için yaygın bir yöntemdir. Bu bölümde, veritabanındaki verileri gruplamak için Group By'ı nasıl kullanacağımızı öğreneceğiz.

Gruplandırılmış sorgu çalıştırmak için bir veya daha fazla alanı nasıl gruplayacağımızı anlatan öğretici örnek.

Varsayalım ki bir kullanıcı tablomuz var ve kullanıcıların ad alanını gruplandırmamız ve her grup için kullanıcı sayısını hesaplamamız gerekiyor. Aşağıda, bu gereksinimi nasıl karşılayacağımızın bir kod örneği bulunmaktadır:

func Yap(ctx context.Context, client *ent.Client) {
    isimler, err := client.User.
        Query().
        GroupBy(user.FieldName).
        Strings(ctx)
    if err != nil {
        log.Fatalf("Gruplu sorgu çalıştırılamadı: %v", err)
    }
    // Her grubun adını çıktıla
    for _, isim := range isimler {
        fmt.Println("Grup adı:", isim)
    }
}

Yukarıdaki kodda, sorgu oluşturucunun GroupBy yöntemini kullanarak hangi alanı gruplamak istediğimizi belirtiriz.

3.2. Birden Fazla Alanı Gruplama ve Toplama

Bazı durumlarda, verileri birden fazla alana göre gruplamak ve her bir grupta toplama işlemleri gerçekleştirmek isteyebiliriz. Aşağıda, bu gereksinimi nasıl karşılayacağımızın bir örneği bulunmaktadır:

Aşağıdaki kod, kullanıcı tablosundaki verileri name ve age alanlarına göre gruplamak ve her bir grupta toplam yaş ve kullanıcı sayısını hesaplamak için nasıl kullanılacağını göstermektedir.

func Yap(ctx context.Context, client *ent.Client) {
    var v []struct {
        Name  string `json:"name"`
        Age   int    `json:"age"`
        Sum   int    `json:"sum"`
        Count int    `json:"count"`
    }
    err := client.User.Query().
        GroupBy(user.FieldName, user.FieldAge).
        Aggregate(ent.Count(), ent.Sum(user.FieldAge)).
        Scan(ctx, &v)
    if err != nil {
        log.Fatalf("Birden fazla alana göre gruplama ve toplama sorgusunu çalıştırmada başarısız oldu: %v", err)
    }
    // Her bir grup için detaylı bilgileri yazdır
    for _, group := range v {
        fmt.Printf("Ad: %s Yaş: %d Toplam: %d Sayı: %d\n", group.Name, group.Age, group.Sum, group.Count)
    }
}

Bu örnekte, kullanıcı tablosundaki verileri sadece name ve age alanlarına göre değil, aynı zamanda her bir grupta toplam kayıt sayısını ve toplam yaşın hesaplanması için Count ve Sum toplama işlevlerinin de kullanıldığı gösterilmektedir.

4. Gruplama ile Having'in Birleştirilmesi

Having ifadesi, Group By işleminden sonra elde edilen toplama sonuçlarını filtreler. Aşağıdaki örnek, her roldeki maksimum yaşa sahip kullanıcıları yalnızca seçmenin nasıl yapıldığını göstermektedir:

func Yap(ctx context.Context, client *ent.Client) {
    var users []struct {
        Id      Int
        Age     Int
        Role    string
    }
    err := client.User.Query().
        Modify(func(s *sql.Selector) {
            s.GroupBy(user.FieldRole)
            s.Having(
                sql.EQ(
                    user.FieldAge,
                    sql.Raw(sql.Max(user.FieldAge)),
                ),
            )
        }).
        ScanX(ctx, &users)
    if err != nil {
        log.Fatalf("Gruplama ile birleştirilmiş Having sorgusunu çalıştırmada başarısız oldu: %v", err)
    }
    // Having koşulunu sağlayan kullanıcı bilgilerini yazdır
    for _, user := range users {
        fmt.Printf("ID: %d Yaş: %d Rol: %s\n", user.Id, user.Age, user.Role)
    }
}

Yukarıdaki kod, her roldeki maksimum yaşa sahip kullanıcıları seçmek için karşılık gelen bir SQL sorgusu oluşturacaktır.