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

Développement SQL Server Discussion :

Requete avec moyennes


Sujet :

Développement SQL Server

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut Requete avec moyennes
    Bonjour,

    Je souhaiterais réaliser dans la même requête :
    - une moyenne des trois montants les plus élevés
    - une moyenne des trois montants les plus bas
    - une moyenne de tous les montants

    Pouvez vous m'aider pour imbriquer les fonctions type "TOP", "AVG" ...

    Merci par avance.

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 763
    Points : 52 554
    Points
    52 554
    Billets dans le blog
    5
    Par défaut
    Utilisez pour ce faire les fonction de fenêtrage : http://sqlpro.developpez.com/article...clause-window/

    Jeun d'essais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CREATE TABLE TM (MONTANT FLOAT)
     
    INSERT INTO TM VALUES (123), (456), (789), (101112)
    la requête :
    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
    WITH T AS (
    SELECT MONTANT, 
           RANK() OVER(ORDER BY MONTANT) AS DOWN,
           RANK() OVER(ORDER BY MONTANT DESC) AS UP,
           AVG(MONTANT) OVER() AS MOYENNE
    FROM   TM),
    TD AS (
    SELECT AVG(MONTANT) AS MOY_BASSE
    FROM   T
    WHERE  DOWN >= 3),
    TU AS (
    SELECT AVG(MONTANT) AS MOY_HAUTE
    FROM   T
    WHERE  UP >= 3),
    TT AS (
    SELECT TOP 1 MOYENNE
    FROM   T)
    SELECT MOYENNE, MOY_BASSE, MOY_HAUTE
    FROM   TD CROSS JOIN TU CROSS JOIN TT
    Le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    MOYENNE                MOY_BASSE              MOY_HAUTE
    ---------------------- ---------------------- ----------------------
    25620                  50950,5                289,5
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    Bonjour et merci pour cette réponse rapide.

    La méthode fonctionne mais les résultats ne sont pas corrects.

    Pour reprendre votre exemple, en moyenne haute vous obtenez 289.5 hors la moyenne de (456), (789), (101112) donne 34119.

    Je vais essayer de regarder en détail.

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 763
    Points : 52 554
    Points
    52 554
    Billets dans le blog
    5
    Par défaut
    Je suis dyslexique... J'inverse beaucoup de choses, comme la droite, la gauche, les haute et les bas

    Voici la chose rectifiée !

    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
    WITH T AS (
    SELECT MONTANT, 
           RANK() OVER(ORDER BY MONTANT) AS DOWN,
           RANK() OVER(ORDER BY MONTANT DESC) AS UP,
           AVG(MONTANT) OVER() AS MOYENNE
    FROM   TM),
    TD AS (
    SELECT AVG(MONTANT) AS MOY_BASSE
    FROM   T
    WHERE  DOWN <= 3),
    TU AS (
    SELECT AVG(MONTANT) AS MOY_HAUTE
    FROM   T
    WHERE  UP <= 3),
    TT AS (
    SELECT TOP 1 MOYENNE
    FROM   T)
    SELECT MOYENNE, MOY_BASSE, MOY_HAUTE
    FROM   TD CROSS JOIN TU CROSS JOIN TT
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    Super, merci beaucoup.

    Est-il possible de ramener la valeur "montant" dans cette requête en complément ?

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    Autant pour moi.

    C'est bon j'ai trouvé ce qu'il me fallait.

    Merci pour tout.

    Bonne soirée

  7. #7
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Une astuce par rapport à la requête de SQLPro pour raccourcir un peu le tout :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    WITH T (MONTANT, DOWN, UP) AS
    (
    SELECT MONTANT
         , RANK() OVER(ORDER BY MONTANT  ASC)
         , RANK() OVER(ORDER BY MONTANT DESC)
      FROM TM
    )
    SELECT AVG(MONTANT)                              as MOYENNE
         , AVG(CASE WHEN DOWN <= 3 THEN MONTANT END) as MOY_BASSE
         , AVG(CASE WHEN UP   <= 3 THEN MONTANT END) as MOY_HAUTE
      FROM T

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    Bonjour,

    Merci.

    J'ai néanmoins oublié une contrainte supplémentaire, à savoir, je dois réaliser ces calculs par rapport à un champ qui correspond à la période.

    Autrement dit, connaitre les différentes moyennes de chaque période.

    Merci

  9. #9
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 763
    Points : 52 554
    Points
    52 554
    Billets dans le blog
    5
    Par défaut
    Rajoutez un groupage !

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    Bonjour et merci.

    Actuellement j'ai :

    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
    WITH TAB_MOY (MONTANT, DOWN, UP, PERIODE) AS
    (
    SELECT RATIO.RAT_Valeur
         , RANK() OVER(ORDER BY RATIO.RAT_Valeur  ASC)
         , RANK() OVER(ORDER BY RATIO.RAT_Valeur DESC)
         , RANK() OVER(ORDER BY RAT_Periode ASC)
      FROM RATIO
      WHERE	(RATIO.RAT_Periode BETWEEN '2010/12' AND '2011/11') AND (RATIO.RAT_Nom = 'Evolution du CA HT')
      GROUP BY RATIO.RAT_Periode, RATIO.RAT_Valeur
    )
    SELECT CAST (AVG(MONTANT) AS DECIMAL(15,2))      AS Moyenne
         , CAST (AVG(CASE WHEN DOWN <= 3 THEN MONTANT END) AS DECIMAL(15,2)) AS MOY_Basse
         , CAST (AVG(CASE WHEN UP   <= 3 THEN MONTANT END) AS DECIMAL(15,2)) AS MOY_Haute
         , PERIODE 
      FROM TAB_MOY, RATIO
      GROUP BY PERIODE
    Seulement, deux problèmes :
    - le champ période n'est plus au format AAAA/MM mais sous forme d'entier et les valeurs calculées en moyennes haute et basse ne sont pas bon.

    Merci

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    ok pour les moyennes (mon jeu de test ne possède que deux montants dans le cas testé).

    Par contre me reste à afficher ma période correctement.

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    J'ai trouvé une solution me permettant de ramener toutes les valeurs nécessaires mais j'ai un problème avec le ORDER qui se trouve avant UNION :

    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
    SELECT 1, RATIO.RAT_Valeur, RATIO.RAT_Periode
    FROM         RATIO INNER JOIN CENTRE ON RATIO.CEN_Code_FK = CENTRE.CEN_Code
    WHERE     (RATIO.RAT_Periode BETWEEN '2010/12' AND '2011/11') AND (CENTRE.CEN_Ville = 'TOULOUSE') AND (RATIO.RAT_Nom = 'Evolution du CA HT')
    UNION
    SELECT 2, AVG(RATIO.RAT_Valeur) AS Moyenne, RATIO.RAT_Periode
    FROM RATIO
    WHERE     (RATIO.RAT_Periode BETWEEN '2010/12' AND '2011/11') AND (RATIO.RAT_Nom = 'Evolution du CA HT')
    GROUP BY RATIO.RAT_Periode
    UNION 
    SELECT TOP 3 3,* FROM
    (	SELECT AVG(RAT_Valeur) AS Moy_Basse, RAT_Periode
    	FROM RATIO
    	WHERE RAT_Periode BETWEEN '2010/12' AND '2011/11' AND RAT_Nom='Evolution du CA HT'
    	GROUP BY RAT_Periode
    ) AS TAB_MOY_BASSE
    ORDER BY Moy_Basse DESC
    UNION
    SELECT TOP 3 4,* FROM
    (	SELECT AVG(RAT_Valeur) AS Moy_Haute, RAT_Periode
    	FROM RATIO
    	WHERE RAT_Periode BETWEEN '2010/12' AND '2011/11' AND RAT_Nom='Evolution du CA HT'
    	GROUP BY RAT_Periode
    ) AS TAB_MOY_HAUTE
    ORDER BY Moy_Haute ASC
    => Moy_Basse non valide
    => UNION : syntaxe incorrecte

    Merci pour votre aide.

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    Etant donné que je ne peux pas utiliser le ORDER BY, il faut certainement que j'intègre un RANK ...

  14. #14
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    L'order by est exécuté en fin de requête (ou par la présence d'un TOP), or un union constitue bien une et une seule requête.
    Il faut donc supprimer celui du milieu, ou rajouter des parenthèses pour mieux séparer les requêtes.

  15. #15
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    136
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 136
    Points : 54
    Points
    54
    Par défaut
    Bonjour,

    Je vous remercie.

    J'ai finalement réussi à terminer cette requête.
    Pour info et si quelqu'un en a besoin, voici ce que ça donne :

    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
    26
    27
    28
    SELECT 1, RATIO.RAT_Valeur, RATIO.RAT_Periode
    FROM         RATIO INNER JOIN CENTRE ON RATIO.CEN_Code_FK = CENTRE.CEN_Code
    WHERE     (RATIO.RAT_Periode BETWEEN '2010/12' AND '2011/11') AND (CENTRE.CEN_Ville = 'Ville') AND (RATIO.RAT_Nom = 'Nom')
     
    UNION
     
    SELECT 2, CAST(AVG(RATIO.RAT_Valeur)AS DECIMAL(15,2)) AS Moyenne , RATIO.RAT_Periode
    FROM RATIO
    WHERE     (RATIO.RAT_Periode BETWEEN '2010/12' AND '2011/11') AND (RATIO.RAT_Nom = 'Nom')
    GROUP BY RATIO.RAT_Periode
     
    UNION 
     
    SELECT 3, CAST (AVG(RAT_Valeur) AS DECIMAL(15,2)) AS MOY_Basse, RAT_Periode 
    FROM	(   SELECT RAT_Valeur, RANK() OVER(PARTITION BY RAT_Periode ORDER BY RATIO.RAT_Valeur ASC) AS Rank_Bas, RAT_Periode
    	FROM RATIO	
    	WHERE RAT_Periode BETWEEN '2010/12' AND '2011/11' AND RAT_Nom='Nom') AS TAB_MOY_BASSE
    WHERE Rank_Bas <=3
    GROUP BY RAT_Periode	
     
    UNION
     
    SELECT 4, CAST (AVG(RAT_Valeur) AS DECIMAL(15,2)) AS MOY_Haute, RAT_Periode 
    FROM	(   SELECT RAT_Valeur, RANK() OVER(PARTITION BY RAT_Periode ORDER BY RATIO.RAT_Valeur DESC) AS Rank_Haut, RAT_Periode
    	FROM RATIO	
    	WHERE RAT_Periode BETWEEN '2010/12' AND '2011/11' AND RAT_Nom='Nom' ) AS TAB_MOY_HAUT
    WHERE Rank_Haut <=3
    GROUP BY RAT_Periode
    Merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. requete avec la valeur NULL
    Par Hinkel dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 12/11/2008, 16h39
  2. requete avec OBCD et visual c++
    Par Anonymous dans le forum MFC
    Réponses: 12
    Dernier message: 18/11/2004, 16h15
  3. Pb d'execution de requete avec un script php
    Par ythierrin dans le forum Requêtes
    Réponses: 3
    Dernier message: 22/08/2003, 14h34
  4. Requete avec une sous-requete... Ne fonctionne qu'a moitie..
    Par mythtvtalk.com dans le forum MS SQL Server
    Réponses: 10
    Dernier message: 18/08/2003, 09h54
  5. Requete avec des décimales
    Par Sandrine75 dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 27/06/2003, 10h18

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