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

WinDev Discussion :

Bizarrerie avec une requête [WD21]


Sujet :

WinDev

  1. #1
    Membre actif Avatar de thierrybatlle
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2005
    Messages
    618
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Tarn (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2005
    Messages : 618
    Points : 222
    Points
    222
    Par défaut Bizarrerie avec une requête
    Bonjour à tous,

    J'ai un problème un peu bizarre sur une requête.
    Voici des captures d'écran pour mettre en place le contexte.

    MCD :
    Nom : MCD.PNG
Affichages : 176
Taille : 22,3 Ko

    Le contenu des 3 tables :
    T_Mouvement :
    Nom : T_Mouvement.PNG
Affichages : 154
Taille : 6,8 Ko
    T_Stock
    Nom : T_Stock.PNG
Affichages : 162
Taille : 6,0 Ko
    T_TypeMouvement
    Nom : T_TypeMouvement.PNG
Affichages : 194
Taille : 3,9 Ko

    Ce que je veux : récupérer tout les mouvements de façon unique avec des informations contenues dans d'autres tables.

    Ma requête 1 :
    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 DISTINCT 
    	T_Produit.IDProduit AS IDProduit,	
    	T_Produit.CodeProduit AS CodeProduit,	
    	T_Produit.Libelle AS Libelle,	
    	T_Mouvement.IDTypeMouvement AS IDTypeMouvement,	
    	T_Mouvement.DateMouvement AS DateMouvement,	
    	T_Stock.NumLot AS NumLot,	
    	T_Mouvement.IDMouvement AS IDMouvement,	
    	T_Stock.Poids AS Poids,	
    	T_Stock.DLUO AS DLUO,	
    	T_Stock.DLC AS DLC
    FROM 
    	T_Produit,	
    	T_Stock,	
    	T_Mouvement
    WHERE 
    	T_Produit.IDProduit = T_Mouvement.IDProduit
    	AND		T_Produit.IDProduit = T_Stock.IDProduit
    	AND
    	(
    		T_Produit.CodeProduit = {ParamCodeProduit}
    		AND	T_Mouvement.IDTypeMouvement <> 2
    	)
    Résultat :
    IDProduit CodeProduit Libellé IDTypeMouvement DateMouvement NumLot IDMouvement Poids DLUO DLC
    3 07612464336538 Lait UHT 1 11/03/2016 140 3 8 NULL 14/07/2004
    3 07612464336538 Lait UHT 1 21/03/2016 140 10 8 NULL 14/07/2004

    Ma requête fonctionne comme je le souhaite

    Dans ma requête 2 je rajoute le champ "quantité" qui est contenu dans la table "Stock", voici 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
    20
    21
    22
    23
    24
    25
     
    SELECT DISTINCT 
    	T_Produit.IDProduit AS IDProduit,	
    	T_Produit.CodeProduit AS CodeProduit,	
    	T_Produit.Libelle AS Libelle,	
    	T_Mouvement.IDTypeMouvement AS IDTypeMouvement,	
    	T_Mouvement.DateMouvement AS DateMouvement,	
    	T_Stock.NumLot AS NumLot,	
    	T_Mouvement.IDMouvement AS IDMouvement,	
    	T_Stock.Poids AS Poids,	
    	T_Stock.DLUO AS DLUO,	
    	T_Stock.DLC AS DLC,	
    	T_Stock.Quantite AS Quantite
    FROM 
    	T_Produit,	
    	T_Stock,	
    	T_Mouvement
    WHERE 
    	T_Produit.IDProduit = T_Mouvement.IDProduit
    	AND		T_Produit.IDProduit = T_Stock.IDProduit
    	AND
    	(
    		T_Produit.CodeProduit = {ParamCodeProduit}
    		AND	T_Mouvement.IDTypeMouvement <> 2
    	)
    Résultat :
    IDProduit CodeProduit Libellé IDTypeMouvement DateMouvement NumLot IDMouvement Poids DLUO DLC Quantité
    3 07612464336538 Lait UHT 1 11/03/2016 140 3 8 NULL 14/07/2004 80,00
    3 07612464336538 Lait UHT 1 21/03/2016 140 10 8 NULL 14/07/2004 80,00
    3 07612464336538 Lait UHT 1 11/03/2016 140 3 8 NULL 14/07/2004 40,00
    3 07612464336538 Lait UHT 1 21/03/2016 140 10 8 NULL 14/07/2004 40,00


    Et là le résultat de ma requête s'affiche avec des doublons !!!!!

    Je vous remercie bien.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Bonjour,
    Je pense que tu as une "erreur" dans tes jointures, car dans le deuxième résultat il n'y a pas de doublons (au sens SQL).
    Si tu regardes les mouvements du 11/03, il y a une ligne avec une quantité de 40, et une autre avec une quantité de 80.
    Le problème est visiblement du au fait qu'un mouvement n'est pas lié à un stock.
    Donc tu as une ligne par stock, d'où les "doublons". Tu aurais 3 lignes de stock, les lignes du résultat seraient "triplées".
    Mais du point de vue SQL, le résultat est normal.

    Tatayo.

  3. #3
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 053
    Points : 9 392
    Points
    9 392
    Par défaut
    Ta requête commence par SELECT DISTINCT

    C'est le mot DISTINCT qui te piège.
    Personnellement je conseille à tous mes collègues de ne jamais utiliser ce mot DISTINCT. C'est un cache-misère , ou plutôt un cache-problème.

    Soit la requête marche et donne le résultat voulu, sans spécifier le mot distinct, soit on veut regrouper X lignes identiques en une seule, et il faut utiliser GROUP BY, et spécifier les colonnes de regroupement.

    Quand tu fait select DISTINCT code_article , quantite from ....
    Le dédoublonnement se fait, non pas sur la colonne code_article toute seule, mais sur toutes les colonnes de la requête.

    Si tu tiens à utiliser DISTINCT, je conseille toujours de faire une première requête , sans le mot DISTINCT. Puis, modifier la requête en ajoutant le mot DISTINCT. Et surtout chercher à comprendre pourquoi c'est pareil, ou pourquoi c'est différent.

    L'avantage de passer par GROUP BY, c'est qu'on lui dit EXPLICITEMENT les colonnes qui servent à faire le regroupement. On contrôle la situation. Avec DISTINCT, on fonce les yeux fermés, et 3 fois sur 4, on se trompe.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    tbc92: je ne suis pas d'accord.
    DISTINCT et GROUP BY ont chacun un rôle différent, et sont tous les deux utiles.
    • DISTINCT permet de dédoublonner le résultat d'une requête.
    • GROUP BY permet de faire des regroupement.


    Ce n'est pas la même chose !

    Par exemple si je veux la liste des clients qui ont acheté un produit donné (mais sans calcul de somme, de moyenne, bref sans regroupement), ma requête va forcément renvoyer des doublons. Comme je veux une liste sans doublon, DISTINCT est tout indiqué. De même dans le cas d'une sous-requête avec un (NOT) IN. Ce n'est pas un regroupement, mais une élimination de doublon.
    Par contre, si je veux disons un chiffre d'affaire par client sur une période, là je vais devoir utiliser un GROUP BY, vu que je dois faire une somme.

    Chaque opérateur son utilité, il faut juste les utiliser à bon escient.

    Par contre je suis d'accord avec toi sur un point: avant de faire la chasse aux doublons dans le résultat d'une requête, il faut se demander pourquoi des lignes sont en doublons. Là se trouve souvent le piège...

    Tatayo.

  5. #5
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 053
    Points : 9 392
    Points
    9 392
    Par défaut
    @tatayo
    On est globalement d'accord, mais ...
    Group by sert à faire des regroupements, oui, mais peut parfaitement être utilisé pour dédoublonner le résultat d'une requête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select distinct id_client from facture
    est strictement équivalent à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select id_client from facture group by id_client
    Peut-être rajouter un order by ... et peut-être une différence en terme de performance (?)

    En fait j'ai tellement vu des gens faire une requête bugguée ... et ajouter un distinct, croyant corriger le bug. Alors qu'en fait ils ne corrigeaient pas le bug, ils le rendaient simplement moins facile à détecter.
    Dans 9 cas sur 10, quand un non-expert utilise la clause distinct, ça cache un loup.
    Alors que quand un non-expert utilise la clause group by, il le fait en connaissance de cause.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Malheureusement, ce n'est pas vrai avec MySQL...
    La requête suivante fonctionne très bien avec ce "sgbd":
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    select client.nom,client.prenom
    from client
    group by client.nom
    Aucune erreur, mais le résultat n'est pas du tout celui souhaité. MySQL va dédoublonner sur le nom seul, et dieu seul sait quel prénom va être retenu pour chaque nom (à priori le premier qu'il trouve !).
    Avec un DISTINCT, on récupère bien une liste de couple unique nom/prénom.
    Ok, c'est un cas particulier, du au support catastrophique de la norme par MySQL.

    Sinon je viens de faire un test rapide sur ma base (MaxDb):
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    explain select distinct art_c_ref from article
    //
    explain select art_c_ref from article group by art_c_ref
    Et le résultat pour la première:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    OWNER	TABLENAME	COLUMN_OR_INDEX	STRATEGY	PAGECOUNT
    TORPEDO	ARTICLE	I_GRPDIM	INDEX SCAN	       235
    			ONLY INDEX ACCESSED	
    			DISTINCT OPTIMIZATION (A)	
    			   RESULT IS NOT COPIED , COSTVALUE IS	       235
    Et pour la deuxième:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    OWNER	TABLENAME	COLUMN_OR_INDEX	STRATEGY	PAGECOUNT
    TORPEDO	ARTICLE	I_GRPDIM	INDEX SCAN	       235
    			ONLY INDEX ACCESSED	
    			     RESULT IS COPIED   , COSTVALUE IS	       705
    Comme on peut le voir, les plans d'exécutions ne sont pas les mêmes, ni le coût de la requête (235 contre 705). Donc non, ces deux requêtes ne sont pas strictement équivalentes, même si elles donnent le même résultat !


    Je vois aussi beaucoup de requêtes mal écrites (il suffit de faire un tour sur la section dédiée du forum), mais je préfère largement expliquer les rôles respectifs de DISTINCT et GROUP BY, et quand les utiliser, plutôt que de conseiller de laisser tomber le premier pour utiliser un "effet secondaire" du deuxième.

    Tatayo.

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

Discussions similaires

  1. Réponses: 11
    Dernier message: 28/12/2004, 16h15
  2. [Recordset] Incompatibilté de type avec une requête
    Par lbourlet dans le forum Access
    Réponses: 2
    Dernier message: 29/10/2004, 15h52
  3. PB avec une requête Count
    Par Marion dans le forum ASP
    Réponses: 7
    Dernier message: 05/07/2004, 12h56
  4. Pb avec une requête
    Par arsgunner dans le forum ASP
    Réponses: 4
    Dernier message: 14/06/2004, 08h40
  5. problème avec une requête imbriquée
    Par jaimepasteevy dans le forum Langage SQL
    Réponses: 13
    Dernier message: 05/12/2003, 10h29

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