1. Introduction à l'analyse des agrégats

L'opération d'agrégation est un concept très important dans les requêtes de base de données. Elle est généralement utilisée pour l'analyse statistique telle que la somme, le comptage, la moyenne, les valeurs maximales et minimales. Ces opérations aident les utilisateurs à extraire des informations significatives à partir d'une grande quantité de données, fournissant un support pour l'analyse des données et la prise de décision. Les fonctions mises en œuvre dans la base de données pour l'agrégation sont généralement appelées fonctions d'agrégat.

2. Opérations d'agrégation de base

2.1 Concept des fonctions d'agrégat

Les fonctions d'agrégat sont des fonctions utilisées dans les langages de requêtes de base de données pour effectuer une série de calculs et renvoyer une seule valeur. En SQL et dans des langages de requête similaires, les fonctions d'agrégat peuvent opérer sur une colonne de données et renvoyer une seule valeur, telles que la somme (SUM), la moyenne (AVG), le comptage (COUNT), le maximum (MAX) et le minimum (MIN). Lorsque nous avons besoin d'effectuer une analyse statistique des données, les fonctions d'agrégat sont des outils importants pour le traitement des ensembles de données et l'extraction de données statistiques.

2.2 Agrégation sur un seul champ

Dans les applications pratiques, l'analyse d'agrégation sur un seul champ est une exigence très courante, souvent utilisée pour obtenir des résultats statistiques tels que la somme, la moyenne, les valeurs maximales et minimales d'une colonne particulière. Supposons que nous ayons une table d'informations de paiement et que nous voulions calculer le montant total payé par les utilisateurs. En utilisant le framework ent, nous pouvons construire une requête à partir de l'entité et appliquer des fonctions d'agrégat comme suit :

func Do(ctx context.Context, client *ent.Client) {
    // Calculer la somme du champ Montant pour l'entité de Paiement
    sum, err := client.Payment.Query().
        Aggregate(
            ent.Sum(payment.Amount),
        ).
        Int(ctx)
    if err != nil {
        log.Fatalf("Échec de l'obtention de la somme : %v", err)
    }
    log.Printf("Montant total des paiements : %d", sum)
}

Dans l'extrait de code ci-dessus, nous initions une requête pour l'entité de paiement en utilisant client.Payment.Query(), puis utilisons la méthode Aggregate() pour appeler la fonction ent.Sum avec payment.Amount comme paramètre pour calculer le montant total des paiements. Nous utilisons .Int(ctx) pour convertir le résultat agrégé en entier et le consigner.

2.3 Agrégation sur plusieurs champs

Dans de nombreux cas, nous devons effectuer des opérations d'agrégation sur plusieurs champs plutôt que sur un seul. Dans cette section, nous allons démontrer comment atteindre une agrégation sur plusieurs champs à travers un exemple.

Dans cet exemple, nous allons additionner, trouver le minimum, trouver le maximum et compter le champ Âge dans la table des animaux.

func Do(ctx context.Context, client *ent.Client) {
    var v []struct {
        Sum, Min, Max, Count int
    }
    err := client.Pet.Query().
        Aggregate(
            ent.Sum(pet.FieldAge), // Somme de l'Âge
            ent.Min(pet.FieldAge), // Âge minimum
            ent.Max(pet.FieldAge), // Âge maximum
            ent.Count(),           // Compter
        ).
        Scan(ctx, &v)
    if err != nil {
        log.Fatalf("Échec de la requête : %v", err)
    }
    // Afficher tous les résultats agrégés
    for _, agg := range v {
        fmt.Printf("Somme : %d Min : %d Max : %d Count : %d\n", agg.Sum, agg.Min, agg.Max, agg.Count)
    }
}

Dans le code ci-dessus, nous utilisons la fonction Aggregate pour effectuer une agrégation sur plusieurs champs, et utilisons la fonction Scan pour stocker les résultats de l'agrégation dans la tranche v. Ensuite, nous itérons à travers v pour afficher tous les résultats agrégés.

3. Application de l'agrégation Group By

3.1. Utilisation de Group By pour regrouper des champs

Dans les opérations de base de données, Group By est une méthode courante pour regrouper des données. Dans cette section, nous allons apprendre comment utiliser Group By pour regrouper des données dans la base de données.

Exemple tutoriel, comment regrouper un ou plusieurs champs en utilisant Group By.

En supposant que nous ayons une table d'utilisateurs et que nous devions regrouper le champ name des utilisateurs et calculer le nombre d'utilisateurs dans chaque groupe. Voici un exemple de code pour atteindre cette exigence :

func Do(ctx context.Context, client *ent.Client) {
    names, err := client.User.
        Query().
        GroupBy(user.FieldName).
        Strings(ctx)
    if err != nil {
        log.Fatalf("Échec de l'exécution de la requête groupée : %v", err)
    }
    // Afficher le nom de chaque groupe
    for _, name := range names {
        fmt.Println("Nom du groupe :", name)
    }
}

Dans le code ci-dessus, nous utilisons la méthode GroupBy du générateur de requêtes pour spécifier quel champ nous voulons regrouper par.

3.2. Regroupement et Agrégation de Plusieurs Champs

Parfois, nous voulons regrouper des données en fonction de plusieurs champs et effectuer des fonctions d'agrégation sur chaque groupe. Voici un exemple de la manière d'atteindre cette exigence :

Le code suivant montre comment regrouper les données dans la table utilisateur en fonction des champs nom et âge, et calculer l'âge total et le nombre d'utilisateurs dans chaque groupe.

func Do(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("Échec de l'exécution de la requête de regroupement et d'agrégation sur plusieurs champs : %v", err)
    }
    // Afficher les informations détaillées pour chaque groupe
    for _, group := range v {
        fmt.Printf("Nom: %s Âge: %d Somme: %d Nombre: %d\n", group.Name, group.Age, group.Sum, group.Count)
    }
}

Dans cet exemple, nous regroupons non seulement les données en fonction des champs nom et âge dans la table utilisateur, mais nous utilisons également les fonctions d'agrégation Count et Sum pour calculer le nombre total d'enregistrements et l'âge total dans chaque groupe.

4. Combinaison de Having avec Group By

La clause Having filtre les résultats d'agrégation obtenus après l'opération Group By. L'exemple suivant montre comment sélectionner uniquement les utilisateurs ayant l'âge maximal dans chaque rôle :

func Do(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("Échec de l'exécution de la requête Having combinée avec Group By : %v", err)
    }
    // Afficher les informations utilisateur satisfaisant la condition Having
    for _, user := range users {
        fmt.Printf("ID: %d Âge: %d Rôle: %s\n", user.Id, user.Age, user.Role)
    }
}

Le code ci-dessus générera une requête SQL équivalente pour sélectionner les utilisateurs ayant l'âge maximal dans chaque rôle.