Partage
  • Partager sur Facebook
  • Partager sur Twitter

AVERAGE sur plusieurs colonnes avec conditions

    2 octobre 2021 à 19:21:58

    Bonjour,

    Je souhaite optimiser une requête SQL. Cette requête me permet d'obtenir des moyennes sur certaines colonnes de ma table en fonction d'un certain nombre de conditions :

    SELECT
        (SELECT AVG(strategie01 + strategie02) FROM questionnaire  WHERE relation = "patron" AND id_name=2 AND ended_at!="0000-00-00 00:00:00" ) as moy_strategie_patron,
        (SELECT AVG(strategie01 + strategie02) FROM questionnaire  WHERE relation = "collaborateur" AND id_name=2 AND ended_at!="0000-00-00 00:00:00" ) as moy_strategie_collaborateur
        

    Seulement voilà,  je répète à chaque fois la partie :

    AND id_name=2 AND ended_at!="0000-00-00 00:00:00"

    Est ce qu'il y aurait une manière pour sélectionner les données qui correspondent à ces deux conditions d'abord et ensuite faire les moyennes de sorte d'optimiser la requête ?

    EDIT : Bon et sinon ça fonctionne pas bien cette requête : alors comment faire la moyenne de plusieurs colonnes en fonction de ces conditions ? Car là il fait plutôt la somme des chiffres qui sont dans les deux col plutôt que de faire la moyenne des deux notes. J'ai essayé plusieurs manières de l'écrire mais je n'ai pas trouvé....

    Merci de votre aide.


    -
    Edité par zazzou 2 octobre 2021 à 19:55:22

    • Partager sur Facebook
    • Partager sur Twitter
      3 octobre 2021 à 1:09:51

      zazzou a écrit:

      il fait plutôt la somme des chiffres qui sont dans les deux col

      Normal, c'est ce que tu as écrit avec l'opérateur +.

      Déjà, comme avait dit Benzouye sur un autre sujet, j'ai peur quand je vois des colonnes ordinales (strategie01, 02, 03 ? ...). C'est un manque de respect d'une des 3 premières forme normale.

      AVG ici va s'utiliser avec GROUP BY relation.

      Ta répétition est un booléen, et tu en as 3 :

      1/ relation = "patron" : A
      2/ relation = "collaborateur" : B
      3/ (id_name=2 AND ended_at="xxx") : C (J'ai regroupé 2 termes).

      Tu veux :

      (A ET C) OU (B ET C) soit en factorisant => C ET (A OU B). Je te laisse retranscrire en SQL.

      T'en dire davantage pourrait amener à t'écrire la requête corrigée.

      Il peut y avoir débat* quant à l'utilisation de la valeur NULL, mais, si le cahier des charges de la BDD est bien conçu, tu devrais accepter la contrainte NULL sur la colonne ended_at. Je suppose que tu cherches la moyenne des stratégies de quelque chose qui n'est pas fini vu la date donnée dans ta condition.

      * La lecture d'une valeur NULL par un utilisateur tiers peut lui faire penser (parfois à raison) qu'il y a une erreur : un cheminement de jointure cassé par exemple.

      • Partager sur Facebook
      • Partager sur Twitter
        3 octobre 2021 à 17:29:43

        Bonjour, merci pour ta réponse.

        CristianoRolando a écrit:

        Déjà, comme avait dit Benzouye sur un autre sujet, j'ai peur quand je vois des colonnes ordinales (strategie01, 02, 03 ? ...). C'est un manque de respect d'une des 3 premières forme normale.

        C'est à dire ?

        J'ai écrit une requête en suivant tes indications. Je récupère deux moyennes mais j'aimerai pouvoir le faire sur plusieurs colonnes. Si j'écris ceci :

        SELECT AVG(strategie01) as moy_strategie_patron FROM questionnaire  WHERE id_name=2 AND ended_at!="0000-00-00 00:00:00" AND (relation = "patron" OR relation = "collaborateur") GROUP BY relation

        J'ai en effet les deux moyennes qui correspondent à strategie01 pour patron et pour collaborateurs.

        Mais j'aimerai une moyenne sur les deux colonnes strategie01 et strategie02. C'est pour cette raison que j'avais testé avec un "+". Qui en effet ne correspond pas puisque ça fait la somme et c'est logique. Mais comment faut il l'écrire alors pour avoir la moyenne de deux colonnes ?

        Je peux me débrouiller avec cette requête en divisant ensuite le résultat par deux mais c'est pas top (j'ai plein d'autres colonnes ensuite).

        Exemple, si j'ai ça :

        strategie01

        strategie02

           

        patron

        25

        75

        patron

        10

        75

        collaborateur

        100

        100

             

        collaborateur

        25

        10

        La moyenne que je souhaite avoir pour patron par ex c'est 46,25. Et pour collaborateur 58,75. Or avec ce que j'ai fait j'obtiens le double.

        Merci de votre aide.

        -
        Edité par zazzou 3 octobre 2021 à 17:41:00

        • Partager sur Facebook
        • Partager sur Twitter
          4 octobre 2021 à 2:43:12

          J'ai réussi, mais, j'ai fait à tâtons.

          Imaginons ta table ainsi :

          table = {id_table INT PK, relation CHAINE, strategie01 INT, strategie02 INT}

          (1, "patron", 25, 75)

          (2, "patron", 10, 75)

          (3, "collaborateur", 100, 100)

          (4, "collaborateur", 25, 10)

          la requête (hors conditions) est :

          SELECT relation, SUM(strategie01+strategie02)/(count(strategie01)+count(strategie02)) as moyenne_strategie_relation
          FROM table
          GROUP BY relation;

          explications de (count(strategie01)+count(strategie02)) et de SUM(strategie01+strategie02) :

          Pour compter le nombre de fois strategie01 et strategie02 par relation :

          SELECT relation, count(strategie01)+count(strategie02)
          FROM table
          GROUP BY relation;

          donnera :

          relation | count .......

          patron | 4

          collaborateur | 4


          Pour faire la somme des stratégies par relation :

          SELECT relation, SUM(strategie01+strategie02)
          FROM table
          GROUP BY relation;

          donnera :

          relation | SUM........

          patron | 185

          collaborateur | 235

          Et 185 / 4 = 46.25, et 235 / 4 = 58.75

          • Partager sur Facebook
          • Partager sur Twitter
            4 octobre 2021 à 9:47:24

            Bonjour,

            CristianoRolando a écrit:

            j'ai peur quand je vois des colonnes ordinales (strategie01, 02, 03 ? ...)

            zazzou a écrit:

            C'est à dire ?

            Lorsque l'on commence à nommer les colonnes avec un numéro, c'est qu'il y a vraisemblablement un problème de conception ... Je ne sais pas quel est exactement ton modèle et combien de colonne nommées "strategieXX" existent dans cette table mais les formes normales imposeraient un modèle avec une relation n,n :

            • relation ( id [pk], libelle ) : table pour stocker tous les types de relations (patron, collaborateur, etc.)
            • strategie ( id [pk], libelle ) : table pour stocker tous les types de stratégies ( stratégie 1, stratégie 2, etc. )
            • personne ( id [pk], nom, prenom, etc. ) : table pour stocker tous les "name"
            • questionnaire ( id [pk], id_relation [fk], id_personne [fk], created_at, ended_at, etc. ) : table pour stocker les questionnaires
            • questionnaire_strategie ( id_questionnaire [pk][fk], id_strategie [pk][fk], valeur ) : table pour stocker la valeur d'une stratégie pour un questionnaire

            Avec ce modèle tu normalises tes données, et tes calculs deviennent plus logique :

            SELECT
            	R.libelle AS nom_relation,
            	AVG( QS.valeur ) AS moyenne
            FROM
            	questionnaire Q
            		INNER JOIN relation R
            			ON Q.id_relation = R.id
            		INNER JOIN questionnaire_strategie QS
            			ON Q.id = S.id_questionnaire
            		INNER JOIN strategie S
            			ON QS.id_strategie = S.id
            		INNER JOIN personne P
            			ON Q.id_personne = P.id
            WHERE
            	Q.id_personne = 2
            	AND Q.ended_at != '0000-00-00 00:00:00'
            	AND S.id IN ( 1, 2 )
            GROUP BY
            	R.libelle

            zazzou a écrit:

            j'aimerai pouvoir le faire sur plusieurs colonnes

            Cela s'appelle un tableau croisé (PIVOT en anglais) et ce n'est pas la logique de base des base de données relationnelles qui travaille de préférence avec des tableaux droits. Cela dit presque tous les SGBDR proposent des fonctions PIVOT pour croiser les tableaux ... MySQL seulement depuis sa version 8.

            Mais, selon moi, ce n'est pas du rôle du SGBDR de croiser les données mais plus du rôle de l'affichage côté applicatif ...

            • Partager sur Facebook
            • Partager sur Twitter
            Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL

            AVERAGE sur plusieurs colonnes avec conditions

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown