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 :

Sous-requête qui retourne les mêmes valeurs


Sujet :

Développement SQL Server

  1. #1
    Membre du Club
    Inscrit en
    Novembre 2010
    Messages
    80
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 80
    Points : 54
    Points
    54
    Par défaut Sous-requête qui retourne les mêmes valeurs
    Bonjour,
    j'ai deux tables client et Produit_achetes_client

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT   SUM(dbo.Produit_achetes_client.Montant) AS Expr1
    FROM         dbo.Produit_achetes_client INNER JOIN
                          dbo.Client ON dbo.Produit_achetes_client.Id_Client = dbo.client.Id_client
    WHERE     (dbo.Produit_achetes_client.Id_Client = 14)
    GROUP BY dbo.Produit_achetes_client.Id_Client, dbo.Produit_achetes_client.Mois, dbo.Produit_achetes_client.Année
    cette sous requête retourne 4 enregistrement différents pour le client N 14
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    23459.65
    56789.65
    92355.65
    17202.65
    mais quand je l'insere dans la requête( il faut ajouter top 1 sinon la requete retourne l'erreur Msg 512, Level 16, State 1, Line 1
    La sous-requête a retourné plusieurs valeurs. Cela n'est pas autorisé quand la sous-requête suit =, !=, <, <= , >, >= ou quand elle est utilisée en tant qu'expression.) suivante elle retourne une seule et même valeur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT       dbo.client.Nom_client,(SELECT   top 1  SUM(dbo.Produit_achetes_client.Montant) AS Expr1
    FROM         dbo.Produit_achetes_client INNER JOIN
                          dbo.Client ON dbo.Produit_achetes_client.Id_Client = dbo.client.Id_client
    WHERE     (dbo.Produit_achetes_client.Id_Client = 14) 
    GROUP BY dbo.Produit_achetes_client.Id_Client, dbo.Produit_achetes_client.Mois, dbo.Produit_achetes_client.Année)
    FROM         dbo.Client inner JOIN
                          dbo.Produit_achetes_client ON dbo.client.Id_client = dbo.Produit_achetes_client.Id_Client
    WHERE     (dbo.client.Id_client = 14) 
    GROUP BY dbo.client.Nom_client, dbo.Produit_achetes_client.Mois, dbo.Produit_achetes_client.Année
    cette requête retourne 4 enregistrements pour le client MESSI qui a le numéro 14
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    MESSI	23459.65
    MESSI	23459.65
    MESSI	23459.65
    MESSI	23459.65
    svp pouvez vous m'aider a résoudre ce problème?

  2. #2
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    733
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2003
    Messages : 733
    Points : 1 668
    Points
    1 668
    Billets dans le blog
    8
    Par défaut
    1 - Il est inutile de préciser le nom du schéma, en l'occurrence dbo, dans les clause SELECT, WHERE et GROUP BY. Cela alourdi le texte de la requête et nuit à la lisibilité du code SQL. Le nom du schéma (exemple dbo et cela peut être autre chose) est cependant requis dans les clauses FROM, JOIN (INNER JOIN, LEFT OUTER JOIN, CROSS JOIN etc.).

    2 -
    Citation Envoyé par messi1987 Voir le message
    mais quand je l'insere dans la requête( il faut ajouter top 1 sinon la requête retourne l'erreur Msg 512, Level 16, State 1, Line 1
    La sous-requête a retourné plusieurs valeurs. Cela n'est pas autorisé quand la sous-requête suit =, !=, <, <= , >, >= ou quand elle est utilisée en tant qu'expression.) suivante elle retourne une seule et même valeur
    Dans votre 2ème requête, la sous-requête telle qu'elle est formulée, est complètement dé-corrélée du reste ! Et donc, c'est tout à fait normal que celle-ci retourne les mêmes résultats c.à.d les 4 enregistrements. L'ajout top 1, permet de corriger l'erreur syntaxique, en effet le résultat de la sous requête doit être atomique. Le top 1 retourne, la première ligne à savoir 23459.65, mais la sous-requête ne reste pas moins dé-corrélée du reste ! ce qui explique pourquoi vous vous retrouver avec la seule et même valeur
    23459.65.
    Par ailleurs, sachez que le SELECT TOP(1), sans préciser au préalable un ORDER BY, est complètement dépourvu de sens ! En effet, il n'y a aucun ordre naturel des lignes. et selon le plan d'exécution choisi par l'optimiseur vous auriez pu obtenir une autre valeur (autre que 23459.65) ! celle-ci sera aussi dupliquée pour toutes les lignes.

    3 - Pour obtenir le résultat escompté, vous devez formuler votre requête comme ceci :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT c.Id_client, c.Nom_client, pac.Mois, pac.Année,  SUM(pac.Montant) AS Expr1	
    FROM  dbo.Client c 
    INNER JOIN dbo.Produit_achetes_client pac
    ON c.Id_client = pac.Id_Client
    WHERE  c.Id_client = 14
    GROUP BY c.Id_client, c.Nom_client, pac.Mois, pac.Année

    A+
    "Une idée mal écrite est une idée fausse !"
    http://hamid-mira.blogspot.com

  3. #3
    Membre du Club
    Inscrit en
    Novembre 2010
    Messages
    80
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 80
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par hmira Voir le message
    1 - Il est inutile de préciser le nom du schéma, en l'occurrence dbo, dans les clause SELECT, WHERE et GROUP BY. Cela alourdi le texte de la requête et nuit à la lisibilité du code SQL. Le nom du schéma (exemple dbo et cela peut être autre chose) est cependant requis dans les clauses FROM, JOIN (INNER JOIN, LEFT OUTER JOIN, CROSS JOIN etc.).

    2 -

    Dans votre 2ème requête, la sous-requête telle qu'elle est formulée, est complètement dé-corrélée du reste ! Et donc, c'est tout à fait normal que celle-ci retourne les mêmes résultats c.à.d les 4 enregistrements. L'ajout top 1, permet de corriger l'erreur syntaxique, en effet le résultat de la sous requête doit être atomique. Le top 1 retourne, la première ligne à savoir 23459.65, mais la sous-requête ne reste pas moins dé-corrélée du reste ! ce qui explique pourquoi vous vous retrouver avec la seule et même valeur
    23459.65.
    Par ailleurs, sachez que le SELECT TOP(1), sans préciser au préalable un ORDER BY, est complètement dépourvu de sens ! En effet, il n'y a aucun ordre naturel des lignes. et selon le plan d'exécution choisi par l'optimiseur vous auriez pu obtenir une autre valeur (autre que 23459.65) ! celle-ci sera aussi dupliquée pour toutes les lignes.

    3 - Pour obtenir le résultat escompté, vous devez formuler votre requête comme ceci :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT c.Id_client, c.Nom_client, pac.Mois, pac.Année,  SUM(pac.Montant) AS Expr1	
    FROM  dbo.Client c 
    INNER JOIN dbo.Produit_achetes_client pac
    ON c.Id_client = pac.Id_Client
    WHERE  c.Id_client = 14
    GROUP BY c.Id_client, c.Nom_client, pac.Mois, pac.Année

    A+
    Je vous remercie M.hamid pour votre explication tres claire ,mais une autre question
    ma requete sql comporte plusieurs sous requêtes avec des conditions cad
    ma table Produit_achetes_client comporte 5 attributs:
    1_id_client
    2_id_produit
    3_mois
    4_année
    5_montant

    id_produit between 1 et 200 ==produits cosmétique
    id_produit between 201 et 400 ==produits electroniques

    donc j'ai deux sous requetes

    1 sous requetes pour avoir la somme des produits cosmetiques qu'il les a achetés pendants chaque mois
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT   SUM(Produit_achetes_client.Montant) AS Expr1
    FROM         Produit_achetes_client INNER JOIN
                          Client ON Produit_achetes_client.Id_Client = client.Id_client
    WHERE     (Produit_achetes_client.Id_Client = 14) and (id_produit between 1 et 200 )
    GROUP BY Produit_achetes_client.Id_Client, Produit_achetes_client.Mois, Produit_achetes_client.Année

    2 sous requetes pour avoir la somme des produits electronique qu'il les a achetés pendants chaque mois
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT   SUM(Produit_achetes_client.Montant) AS Expr1
    FROM         Produit_achetes_client INNER JOIN
                          Client ON Produit_achetes_client.Id_Client = client.Id_client
    WHERE     (Produit_achetes_client.Id_Client = 14) and (id_produit between 201 et 400 )
    GROUP BY Produit_achetes_client.Id_Client, Produit_achetes_client.Mois, Produit_achetes_client.Année
    a la fin je veux cette resultat
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT c.Id_client, c.Nom_client, pac.Mois, pac.Année,  SUM(pac.Montant cosmitique) AS Expr1	,SUM(pac.Montant ELECTRONIQUES) AS Expr2
    FROM  dbo.Client c 
    INNER JOIN dbo.Produit_achetes_client pac
    ON c.Id_client = pac.Id_Client
    WHERE  c.Id_client = 14
    GROUP BY c.Id_client, c.Nom_client, pac.Mois, pac.Année

    Merci de votre aide

  4. #4
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    Il suffit de ne sommer que lorsque le type correspond à la catégorie voulue :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    SELECT c.Id_client, c.Nom_client, pac.Mois, pac.Année
        ,  SUM(CASE WHEN id_produit BETWEEN 1 et 200 THEN  pac.Montant END) AS TotalCosmetique
        ,  SUM(CASE WHEN id_produit BETWEEN 201 et 400 THEN  pac.Montant END) AS TotalElectronique
    FROM  dbo.Client c 
    INNER JOIN dbo.Produit_achetes_client pac
    ON c.Id_client = pac.Id_Client
    WHERE  c.Id_client = 14
    GROUP BY c.Id_client, c.Nom_client, pac.Mois, pac.Année

  5. #5
    Membre expérimenté

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    733
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2003
    Messages : 733
    Points : 1 668
    Points
    1 668
    Billets dans le blog
    8
    Par défaut
    Oui , merci aieeeuuuuu d'après pris le relais et apporter une réponse très juste à cette discussion.

    Juste une petite remarque. Il faut ajouter dans l'instruction CASE le ELSE pour fermer l'étendu des conditions possibles. En effet, parmi les bonnes pratiques, il est recommandé de toujours rajouter un ELSE final dans les instructions CASE
    Le résultat final ne changera évidement pas mais c'est juste pour les bonnes pratiques et pour la forme !
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT c.Id_client, c.Nom_client, pac.Mois, pac.Année
        ,  SUM(CASE WHEN id_produit BETWEEN 1 et 200 THEN  pac.Montant ELSE 0 END) AS TotalCosmetique
        ,  SUM(CASE WHEN id_produit BETWEEN 201 et 400 THEN  pac.Montant ELSE 0 END) AS TotalElectronique
    FROM  dbo.Client c 
    INNER JOIN dbo.Produit_achetes_client pac
    ON c.Id_client = pac.Id_Client
    WHERE  c.Id_client = 14
    GROUP BY c.Id_client, c.Nom_client, pac.Mois, pac.Année
    A+
    "Une idée mal écrite est une idée fausse !"
    http://hamid-mira.blogspot.com

  6. #6
    Membre du Club
    Inscrit en
    Novembre 2010
    Messages
    80
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 80
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par hmira Voir le message
    Oui , merci aieeeuuuuu d'après pris le relais et apporter une réponse très juste à cette discussion.

    Juste une petite remarque. Il faut ajouter dans l'instruction CASE le ELSE pour fermer l'étendu des conditions possibles. En effet, parmi les bonnes pratiques, il est recommandé de toujours rajouter un ELSE final dans les instructions CASE
    Le résultat final ne changera évidement pas mais c'est juste pour les bonnes pratiques et pour la forme !
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT c.Id_client, c.Nom_client, pac.Mois, pac.Année
        ,  SUM(CASE WHEN id_produit BETWEEN 1 et 200 THEN  pac.Montant ELSE 0 END) AS TotalCosmetique
        ,  SUM(CASE WHEN id_produit BETWEEN 201 et 400 THEN  pac.Montant ELSE 0 END) AS TotalElectronique
    FROM  dbo.Client c 
    INNER JOIN dbo.Produit_achetes_client pac
    ON c.Id_client = pac.Id_Client
    WHERE  c.Id_client = 14
    GROUP BY c.Id_client, c.Nom_client, pac.Mois, pac.Année
    A+
    Merci bcp grace a vous hmira et aieeeuuuuuu j'ai appris une nouvelle technique

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 19/06/2011, 18h48
  2. Réponses: 4
    Dernier message: 13/06/2011, 17h41
  3. Réponses: 4
    Dernier message: 13/03/2011, 14h41
  4. [XL-2003] supprimer des lignes qui ont les même valeurs
    Par Neptune64 dans le forum Excel
    Réponses: 1
    Dernier message: 09/08/2009, 00h30
  5. Réponses: 5
    Dernier message: 27/05/2008, 08h02

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