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

MS SQL Server Discussion :

Group by exhaustif ?


Sujet :

MS SQL Server

  1. #1
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut Group by exhaustif ?
    Bonjour

    Je suis un peu stupéfait de la maniere de devoir traiter les group by en SQL Server !

    J'essaye un query qui fonctionne bien en MySql

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT 
    count(*),
    PersID AS PersID,
    PersNom AS Nom,
    PersPrenom AS Prenom,
    PersSexID AS Sex,
    PaysNomFR AS Nationalite,
    PersGSM AS Mobile,
    PersTel AS Tel,
    PersEmail AS Email
    FROM Personnes_tbl
    INNER JOIN Link_Contacts_tbl ON PersID = CtacPersID 
    LEFT OUTER JOIN Pays_tbl ON PersNationID = PaysID 
    group by (PersID)
    Le count(*) associé au group by me permettent d'avoir le nombre de contact lié a chaque Personnes

    En MySql ce genre de query fonctionne tres bien et la syntaxe me semble logique

    En SQL Server ca ne fonctionne pas du tout et quelquiun vient de me dire que je dois inclure TOUS les éléments dans le group by

    J'ai essayé et effectivement ca fonctionne mais si je comprends bien, :
    Ca signifie que SQL Serveur est incapable de faire un Group by selectif ?
    Je n'ose pas y croire

    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
    17
    18
    19
    20
    21
    SELECT   
    count(*),
    PersID AS PersID,
    PersNom AS Nom,
    PersPrenom AS Prenom,
    PersSexID AS Sex,
    PaysNomFR AS Nationalite,
    PersGSM AS Mobile,
    PersTel AS Tel,
    PersEmail AS Email
    FROM Personnes_tbl
    INNER JOIN Link_Contacts_tbl ON PersID = CtacPersID 
    LEFT OUTER JOIN Pays_tbl ON PersNationID = PaysID 
    group by PersID,
    PersNom,
    PersPrenom,
    PersSexID,
    PaysNomFR,
    PersGSM,
    PersTel,
    PersEmail
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  2. #2
    Expert éminent sénior
    Avatar de mikedavem
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2005
    Messages
    5 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Distribution

    Informations forums :
    Inscription : Août 2005
    Messages : 5 450
    Points : 12 891
    Points
    12 891
    Par défaut
    Bonjour,

    SQL Server respecte la norme SQL 2003 qui impose qu'une colonne utilisée dans une expression de la clause SELECT doit figurer dans la clause GROUP BY.

    Mysql ne respecte pas cette norme à priori.

    De plus je trouve que sémantiquement parlant ce group by "sélectif" induit en erreur.

    GROUP BY personID = Création d'aggrégats en fonction de la colonne personID, ce qui est évidemment faux dans le cadre de votre requête.

    Effectivement cela est un peu plus long à écrire mais la sémantique reste claire.

    ++

  3. #3
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Merci mikedavem

    Tu parle d'expression

    SQL Server respecte la norme SQL 2003 qui impose qu'une colonne utilisée dans une expression de la clause SELECT doit figurer dans la clause GROUP BY.
    Mais si je fais la requete ci-apres, j'inclus bien la colone PersID utilisée dans l'expression Count() du select Or ca ne marche pas mieux !!
    Je reste obligé d'inclure TOUTES les colonnes du select
    Dans ce cas a quoi bon !
    L'engine pourrait faire le travail pour moi si c'est pour systématiquement ecrire deux fois la meme chose
    Et ca signifie en plus qu'il est impossible de faire un count group by sur un seul champ

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT
        Count(PersID),
    	PersID AS PersID,
    	PersNom AS Nom,
    	PersPrenom AS Prenom,
    	PersSexID AS Sex,
    	PaysNomFR AS Nationalite,
    	PersGSM AS Mobile,
    	PersTel AS Tel,
    	PersEmail AS Email
    FROM Personnes_tbl
    	INNER JOIN Link_Contacts_tbl ON PersID = CtacPersID 
    	LEFT OUTER JOIN Pays_tbl ON PersNationID = PaysID 
    Group by PersID
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  4. #4
    Expert éminent sénior
    Avatar de mikedavem
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2005
    Messages
    5 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Distribution

    Informations forums :
    Inscription : Août 2005
    Messages : 5 450
    Points : 12 891
    Points
    12 891
    Par défaut
    Il faut revenir à la définition de GROUP BY :


    Groupe un ensemble sélectionné (agrégat) de lignes dans un ensemble de lignes de synthèse par les valeurs d'une ou plusieurs colonnes ou expressions.


    Qu'est ce qu'un agrégat ? Un agrégat est un cumul de données selon certains axes d'analyse.

    Donc COUNT(PersonID) est un bien agrégat en fonction de la colonne PersonID

    Mais :
    PersNom n'est pas un agrégat en fonction de la colonne PersonID.
    PersPrenom n'est pas un agrégat en fonction de la colonne PersonID
    ...
    etc

    ++
    ..

  5. #5
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Merci mikedavem

    Mais ca signifie qu'un truc tres simple que je peux faire un MySql :

    Voici un exemple elementaire qui'il est donc impossible de faire en MS Sql sans faire un select count temporaire


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT
    count(addrid),
    ritstat.`date`,
    ritstat.addrID
    FROM
    ritstat
    GROUP BY (addrid)
    J'ai le count des dates sur une adresse


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT
    count(date),
    ritstat.`date`,
    ritstat.addrID
    FROM
    ritstat
    GROUP BY (date)
    J'ai le count des adresses sur une date


    Est BEAUCOUP plus tordu a faire en MS Sql (j'ai fini par trouver la syntaxe pour mon cas )

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    SELECT 
    	pers.PersID AS PersID,
    	pers.PersNom AS Nom,
    	pers.PersPrenom AS Prenom,
    	pers.PersSexID AS Sex,
    	pays.PaysNomFR AS Nationalite,
    	pers.PersGSM AS Mobile,
    	pers.PersTel AS Tel,
    	pers.PersEmail AS Email,
    	cnt.[cnt] AS Instances
    FROM
    	Personnes_tbl AS pers
    	INNER JOIN Link_Contacts_tbl AS conts ON pers.PersID = conts.CtacPersID 
    	LEFT OUTER JOIN Pays_tbl AS pays ON pers.PersNationID = pays.PaysID 
    	INNER JOIN (
    		SELECT
    			PersID AS [persId],
    			count(PersID) as cnt 
    		FROM
    			Personnes_tbl AS pt
    			INNER JOIN Link_Contacts_tbl AS lc ON pt.PersID = lc.CtacPersID 
    		group by
    			PersID
    		)
    		AS cnt ON cnt.[persId] = pers.[PersId]
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  6. #6
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 453
    Points : 18 383
    Points
    18 383
    Par défaut
    Citation Envoyé par mikedavem Voir le message
    SQL Server respecte la norme SQL 2003 qui impose qu'une colonne utilisée dans une expression de la clause SELECT doit figurer dans la clause GROUP BY.
    Je ne pense pas que ceci soit juste.
    Pour moi l'aggrégat se fait par rapport aux colonnes du GROUP BY, et la partie SELECT vient après.

    La requête suivante, forcément pas très utile, n'est pas fausse :
    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    WITH Test(annee, trim, mois) AS
    (
    select 2009, 1,  1 union all
    select 2009, 1,  2 union all
    select 2009, 1,  3 union all
    select 2009, 2,  4 union all
    select 2009, 2,  5 union all
    select 2009, 2,  6 union all
    select 2009, 3,  7 union all
    select 2009, 3,  8 union all
    select 2009, 3,  9 union all
    select 2009, 4, 10 union all
    select 2009, 4, 11 union all
    select 2009, 4, 12
    )
      select annee, COUNT(*) as nb
        from Test
    group by annee, trim;
     
    annee       nb
    ----------- -----------
    2009        3
    2009        3
    2009        3
    2009        3
    Celle-ci non plus n'est pas fausse mais une fois encore pas vraiment exploitable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      select annee, case when trim in (1, 2, 3) then 1 else 2 end as newtrim, COUNT(*) as nb
        from Test
    group by annee, trim;
     
    annee       newtrim     nb
    ----------- ----------- -----------
    2009        1           3
    2009        1           3
    2009        1           3
    2009        2           3

  7. #7
    Expert éminent sénior
    Avatar de mikedavem
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2005
    Messages
    5 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Distribution

    Informations forums :
    Inscription : Août 2005
    Messages : 5 450
    Points : 12 891
    Points
    12 891
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT annee, COUNT(*) AS nb
        FROM Test
    GROUP BY annee, trim;
    L'agrégat est ici "annee, trim". Dans ton 1er cas la requête fonctionne car aucune colonne de la clause SELECT ne fait pas parti la clause GROUP BY.

    Cette même requête fonctionnerait avec l'ajout de la colonne trim dans la clause SELECT car elle fait parti de la clause GROUP BY.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT annee,trim, COUNT(*) AS nb
        FROM Test
    GROUP BY annee, trim;
    Par contre ceci ne fonctionnerait pas car la colonne mois ne fait pas parti de la clause GROUP BY :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT annee,mois, COUNT(*) AS nb
        FROM Test
    GROUP BY annee, trim;
    On en revient donc à la norme :
    Une colonne utilisée dans une expression de la clause SELECT doit figurer dans la clause GROUP BY.

    Même chose pour ton 2ème exemple.

    ++

  8. #8
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 453
    Points : 18 383
    Points
    18 383
    Par défaut
    Au temps pour moi, j'avais lu à l'envers.

Discussions similaires

  1. [CR8] Groupes nommés par ordre spécifié
    Par PschittN dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 17/05/2004, 23h46
  2. Selection de Groupes ki ne sont pas sous groupes...
    Par superdada dans le forum Langage SQL
    Réponses: 2
    Dernier message: 23/07/2003, 14h42
  3. [RaveReport] - Bloquer groupe sur une page
    Par muaddib dans le forum Rave
    Réponses: 3
    Dernier message: 25/02/2003, 16h21
  4. gestion des groupes
    Par muaddib dans le forum QuickReport
    Réponses: 3
    Dernier message: 31/12/2002, 11h01

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