IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Linq Discussion :

Comment utilisez Group By et Sum en Linq


Sujet :

Linq

  1. #1
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut Comment utiliser Include() avec Group By
    Bonjour,

    Je cherche à appliquer un Group By sur 2 colonnes à la requête Linq suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Return (From parution In Context.parutions.Include("messages").Include("messages.plansmedias.campagnes").Include("messages.plansmedias.campagnes.annonceurs").Include("messages.tarifs.produitsvendus.supports.medias") _
                    Where parution.DateParution.StartsWith(argYear & "-" & argMonth) And parution.messages.tarifs.produitsvendus.distributions.fournisseurs.IdFournisseur = 8 _
                    Select parution).ToList
    Je suis très novice en dotnet surtout avec Linq que j'ai tout de suite eu le coup de foudre
    Je veux faire un Group By sur messages.plansmedias.campagnes.annonceurs.IdAnnonceur et messages.plansmedias.campagnes.IdCampagne
    Mais je ne sais pas quoi d'abord mettre après Into

    Ensuite il y a des sommes à faire pour les groupe by sur la table messages, 2 sommes Sum(messages.Montant) et Sum(messages.NombreParution)

    Il s'agit ici de Linq To Entities d'une BD liée de clés étrangères

  2. #2
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Par exemple, où est le hic dans ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	Public Shared Function GetParutionsByMonthYearFournisseur(Optional ByVal argMonth As String = "", Optional ByVal argYear As String = "") As List(Of parutions)
            Return (From parution In Context.parutions.Include("messages").Include("messages.plansmedias.campagnes").Include("messages.plansmedias.campagnes.annonceurs").Include("messages.tarifs.produitsvendus.supports.medias") _
            Where parution.DateParution.StartsWith(argYear & "-" & argMonth) And parution.messages.tarifs.produitsvendus.distributions.fournisseurs.IdFournisseur = 8 _
            Group By parution.messages.plansmedias.campagnes.IdCampagne _
            Into Group).ToList
    	End Function
    Avant l'utilisation de Group By Into, ça marchait mais après
    Value of type 'System.Collections.Generic.List(Of <anonymous type>)' cannot be converted to 'System.Collections.Generic.List(Of LogicielMediaBO.parutions)'.

  3. #3
    Expert confirmé
    Avatar de Nicolas Esprit
    Homme Profil pro
    Consultant en technologies
    Inscrit en
    Février 2010
    Messages
    1 467
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Consultant en technologies
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 1 467
    Points : 4 066
    Points
    4 066
    Par défaut
    Citation Envoyé par randriano Voir le message
    Value of type 'System.Collections.Generic.List(Of <anonymous type>)' cannot be converted to 'System.Collections.Generic.List(Of LogicielMediaBO.parutions)'.
    Ce genre d'erreur arrive lorsqu'on oublie un select dans la requête, du coup le ToList ne peut fonctionner.

    En espérant t'avoir aidé.

  4. #4
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Là je comprends le message d'erreur mais je ne sais pas quoi mettre après Select ici

    Si je mets "Select parution", j'ai l'erreur
    Name 'parution' is either not declared or not in the current scope.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations forums :
    Inscription : Octobre 2009
    Messages : 90
    Points : 54
    Points
    54
    Par défaut
    Je n'ai jamais utilisé LinQ seulement tapée mes requêtes à la main, mais normalement c'est la même chose donc. Quand tu fais un Group By tu es obligé de le faire sur tout les éléments de la requête sauf ceux dont tu fais la somme

    par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select SUM(champs1), champs2, champs3, champs4 from table 1 group by champs2, champs3, champs4 having champs2= and champ3 =;

  6. #6
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    La requête que j'ai envie de faire est assez clair en SQL: group by sur 2 champs de 2 tables, mais avec une jointure sur plus de 8 tables donc très difficile

    C'est la raison du choix de Linq, il suffit d'utiliser des Include(), de plus je suis sous Linq to Entities

    Mon soucis c'est que je suis novice en Linq et je n'arrive même pas à utiliser un Group By sur un champ

    Dépêche: http://geekswithblogs.net/SudheersBl...11/132758.aspx
    Là au moins j'ai la confirmation que Include() ne va pas avec Group By mais comment esquiver cela? Est-il possible de grouper après le résultat d'un query utilisant Include() comme je fais?

  7. #7
    Membre Expert

    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Juin 2003
    Messages
    4 506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2003
    Messages : 4 506
    Points : 5 723
    Points
    5 723
    Par défaut
    Tu peux le faire en 2 étapes. 1 tu récupères le résultat avec les includes. Puis 2 ton fais le group by sur le résultat de ta première requête. Plutôt que d'essayer de tout faire en 1 requête.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    var ResultWithInclude= from s in ...Include(..).Include()
     
    var ResultWithGroupBy= from r in ResultWithInclude
                                     group by ...
    .

  8. #8
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Merci Hegros, bonne technique et c'est ce que j'ai fais et ça marche. J'ai plutôt mis le résultat du query avec les Include() dans un List(Of T)

    Le soucis avec Group By maintenant c'est comment obtenir les champs qui ne sont pas à regrouper et à sommer ou compter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    colParutionsMonthYear = (From p In tmpcolParutionsMonthYear _
    		 Group By p.FournisseurId, p.Campagne _
    		 Into Group _
    		 Select New ParutionsMonthYear With {.Fournisseur = "Fournisseur", _
    		 .FournisseurId = FournisseurId, _
    		  .Annonceur = "Annonceur", _
    		  .Campagne = Campagne, _
    		  .Media = "Web", _
    		  .Format = "N/A", _
    		  .NombreParution = Group.Sum(Function(p) p.NombreParution), _
    		  .MontantNet = Group.Sum(Function(p) p.MontantNet), _
    		  .Commission = (Group.Sum(Function(p) p.MontantNet) * 8) / 100 _
    		  } _
    		).ToList
    Par ex, ici j'ai mis des valeurs constantes pour ces champs car je ne sais pas comment les avoir?

    Bref, l'équivalent d'un SELECT *, SUM(), SUM()

  9. #9
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    Bonjour,

    Je ne suis pas sûr que cela soit ce que tu espères, mais dans le doute mieux que je le poste, il faudra également vérifier car sans données exemple pour tester ce n'est pas aussi facile

    Code VB.Net : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
            Dim result = From p In tmpcolParutionsMonthYear
                         Join g In
                         (
                             From p In tmpcolParutionsMonthYear
                             Group p By p.FournisseurId, p.Campagne Into Group
                             Let parution = Group.Sum(Function(tmp) tmp.NombreParution)
                             Let net = Group.Sum(Function(tmp) tmp.MontantNet)
                             Let com = net * 8 / 100
                         )
                         On p.FournisseurId Equals g.FournisseurId And p.Campagne Equals g.Campagne
                         Select New With
                                {
                                    p.Fournisseur,
                                    p.FournisseurId,
                                    p.Annonceur,
                                    p.Campagne,
                                    p.Media,
                                    p.Format,
                                    .NombreParution = g.parution,
                                    .MontantNet = g.net,
                                    .Commission = g.com
                                }

    En espérant que cela serve

  10. #10
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Merci Sehnsucht d'avoir pris beaucoup de peine
    En fait pour la jointure entre (), il s'agit plutôt de tmp au lieu de p non?

    J'ai testé le code comme suit
    Code vb.net : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    		colParutionsMonthYear = (From p In tmpcolParutionsMonthYear _
    		 Join g In _
    		 ( _
    		From tmp In tmpcolParutionsMonthYear _
    		  Group tmp By tmp.FournisseurId, tmp.Campagne Into Group _
    		Let parution = Group.Sum(Function(tmp) tmp.NombreParution) _
    		Let Net = Group.Sum(Function(tmp) tmp.MontantNet) _
    		Let com = Net * 8 / 100 _
    		 ) _
    		 On p.FournisseurId Equals g.FournisseurId And p.Campagne Equals g.Campagne _
    		 Select New ParutionsMonthYear With _
    		  { _
    		   .Fournisseur = p.Fournisseur, _
    		   .FournisseurId = p.FournisseurId, _
    		   .Annonceur = p.Annonceur, _
    		   .Campagne = p.Campagne, _
    		   .Media = p.Media, _
    		   .Format = p.Format, _
    		   .NombreParution = g.parution, _
    		   .MontantNet = g.Net, _
    		.Commission = g.com _
    		  } _
    		 ).ToList
    Le soucis c'est que ça ne fait pas de groupement car le nombre de résultat est le même que tmpcolParutionsMonthYear .Count()
    A partir de mon précédent code, il n'est donc pas possible d'obtenir la valeur des autres champs que par JOIN??

  11. #11
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    En ce qui concerne la variable p interne, elle est différente de celle du début donc non ce n'était pas le même qu'au début et on pouvait la nommer comme on veut, d'ailleurs j'ai pas fais gaffe sinon je l'aurais nommée autrement que p qui était déjà utilisé (merci les copier/coller à tout va pour réunir tous mes bouts de test )

    Sinon je me suis créé une petite classe avec des données bidons pour faire des essais, en croisant les doigts pour que ça colle avec celles que tu as re- et d'après mes résultats ce qui suit semble fonctionner, mis à part le coup du Distinct, que j'ai retourné dans tous les sens sans succès donc voilà le code:

    Code VB.Net : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     
    Public Class ColParutionsMonthYear
        'Normalement ça se fait pas les champs publics mais c'est juste pour le test
        Public FournisseurId, NombreParution As Integer
        Public Fournisseur, Annonceur, Campagne, Media, Format As String
        Public MontantNet, Commission As Decimal
    End Class
     
    Module Essai
        Public Sub Test()
            Dim tmpcolParutionsMonthYear() As ColParutionsMonthYear =
                {
                    New ColParutionsMonthYear With {.FournisseurId = 1, .Campagne = "1", .NombreParution = 11, .MontantNet = 11.11D},
                    New ColParutionsMonthYear With {.FournisseurId = 1, .Campagne = "2", .NombreParution = 12, .MontantNet = 12.12D},
                    New ColParutionsMonthYear With {.FournisseurId = 2, .Campagne = "1", .NombreParution = 21, .MontantNet = 21.21D},
                    New ColParutionsMonthYear With {.FournisseurId = 3, .Campagne = "3", .NombreParution = 33, .MontantNet = 33.33D},
                    New ColParutionsMonthYear With {.FournisseurId = 1, .Campagne = "1", .NombreParution = 1010, .MontantNet = 1010.101D}
                }
     
            Dim result =
                (
                    From p In tmpcolParutionsMonthYear
                    Group Join p2 In tmpcolParutionsMonthYear
                    On p.FournisseurId Equals p2.FournisseurId And p.Campagne Equals p2.Campagne
                    Into parution = Sum(p2.NombreParution),
                    net = Sum(p2.MontantNet)
                    Select New ColParutionsMonthYear With
                           {
                               .FournisseurId = p.FournisseurId,
                               .Fournisseur = p.Fournisseur,
                               .Annonceur = p.Annonceur,
                               .Campagne = p.Campagne,
                               .Media = p.Media,
                               .Format = p.Format,
                               .NombreParution = parution,
                               .MontantNet = net,
                               .Commission = net * 8 / 100
                           }
                ).Distinct(New ParutionComparer).ToList
        End Sub
    End Module
     
    Public Class ParutionComparer
        Implements IEqualityComparer(Of ColParutionsMonthYear)
     
        Public Overloads Function Equals(ByVal x As ColParutionsMonthYear, ByVal y As ColParutionsMonthYear) As Boolean Implements IEqualityComparer(Of ColParutionsMonthYear).Equals
            Return x.FournisseurId = y.FournisseurId AndAlso x.Campagne = y.Campagne
        End Function
     
        Public Overloads Function GetHashCode(ByVal obj As ColParutionsMonthYear) As Integer Implements IEqualityComparer(Of ColParutionsMonthYear).GetHashCode
            Return obj.GetHashCode
        End Function
     
    End Class

    Donc à tester et qui sait peu être que ça inspirera quelqu'un d'autre, qui trouvera la solution pour le Distinct voire une meilleure idée

  12. #12
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Wow, tu as réussi à faire tout ce code ainsi d'avoir compris mes données, chapeau mais je ne sais pas si c'est moi qui copie bêtement car j'ai toujours le même nombre de lignes de résultat que tmpcolParutionsMonthYear

    En fait c'est que je ne comprends pas avec le GROUP BY en LINQ c'est que ne peut-on plus faire des requêtes comme (en sql):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT Fournisseur, FournisseurId, Campagne, Media, Format, Sum(NombreParution), Sum(MontantNet), Sum(MontantNet)*Commission/100
    From tmpcolParutionsMonthYear
    GROUP BY FournisseurId, Campagne
    Je ne veux qu'obtenir tous mes champs avec les nouveaux calculés

  13. #13
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    À moins de dire une énorme boulette mais il ne me semble pas cette requête là n'existe pas (ou alors dans une norme ancienne du SQL voire dans du SQL non-normé)

    En SQL, tout champ qui n'est pas le résultat d'une agrégation (COUNT, SUM, AVG ...) se doit de figurer dans la clause GROUP BY, si l'on souhaite pouvoir le mettre dans la clause SELECT, ainsi sont correctes les requêtes suivantes :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    --Requete 1
    SELECT
        FournisseurId,
        Campagne,
        SUM(NombreParution) AS TotalParution,
        SUM(MontantNet) AS MontantNetTotal,
    FROM
        tmpcolParutionsMonthYear
    GROUP BY
        FournisseurId,
        Campagne
     
    --Requete 2
    SELECT
        SUM(NombreParution) AS TotalParution,
        SUM(MontantNet) AS MontantNetTotal,
    FROM
        tmpcolParutionsMonthYear
    GROUP BY
        FournisseurId,
        Campagne
     
    --Requete 3
    SELECT
        FournisseurId,
        Campagne,
        SUM(NombreParution) AS TotalParution,
        SUM(MontantNet) AS MontantNetTotal,
        SUM(MontantNet) * Commission / 100 As TotalCommission
    FROM
        tmpcolParutionsMonthYear
    GROUP BY
        FournisseurId,
        Campagne,
        Commission

    Bon après je ne fais pas du SQL tous les jours, donc s'il y a réellement un moyen, je m'excuserais d'avoir dis que c'était faux, mais il ne me semble vraiment pas.

  14. #14
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Si ça marche mais en effet, c'est peut-être non-normé, on ne saurait quoi mettre dans ces champs, j'ai remarqué que c'est la 1ère valeur trouvée avant le groupement

    Une question: que contient Group car il semble que c'est un array? Pourquoi en VB.NET on ne peut pas faire Into G, Into uiop, etc comme en C# mais juste Into Group

  15. #15
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Group est effectivement un tableau que j'utilise ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
     
    			colParutionsYear_tmp = (From p In tmpcolParutionsYear _
    			  Order By p.FournisseurId, p.Mois, p.Media, p.Format _
    			 Group By p.FournisseurId, p.Mois, p.Media, p.Format _
    			 Into Group _
    			 Select New ParutionsYear With {.Fournisseur = Group(0).Fournisseur, _
    			 .FournisseurId = FournisseurId, _
    			  .Mois = Mois, _
    			  .Media = Media, _
    			  .Format = Format, _
    			  .NombreParution = Group.Sum(Function(p) p.NombreParution), _
    			  .MontantNet = Group.Sum(Function(p) p.MontantNet), _
    			  .Commission = (.MontantNet * Group(0).Commission) / 100 _
    			  } _
    			).ToList
    ici Group(0).Fournisseur

Discussions similaires

  1. Comment utilisez-vous Outlook
    Par Dolphy35 dans le forum Outlook
    Réponses: 40
    Dernier message: 16/12/2018, 18h30
  2. Comment programmer la construction d'une requête LINQ ?
    Par SpongeRobert dans le forum Linq
    Réponses: 4
    Dernier message: 01/09/2009, 11h05
  3. Réponses: 7
    Dernier message: 06/04/2009, 17h29
  4. Réponses: 3
    Dernier message: 29/01/2009, 09h49
  5. GROUP BY et SUM
    Par bchristo dans le forum Langage SQL
    Réponses: 8
    Dernier message: 02/12/2005, 16h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo