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

Requêtes MySQL Discussion :

INNER JOIN et SELECT


Sujet :

Requêtes MySQL

  1. #1
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Points : 2
    Points
    2
    Par défaut INNER JOIN et SELECT
    Bonjour,

    Je bloque sur une requête imbriquée sur un left join. Je vous soumets mon problème en espérant que vous puissiez m'aider.

    J'ai une table de contacts avec entre autres le champ idcontact.
    Une table event avec entre autres les champs idcontact / idevent / type / datecrea (date de création).

    La liaison est de type 1-N. 1 contact, plusieurs événements.

    Dans ma table event, j'ai plusieurs types possibles :
    - type1
    - type2
    - type3
    - type4

    Je cherche à récupérer dans une requête tous les contacts qui ont au moins un événement en excluant les contacts qui ont un événement de type "type2" sauf s'il existe un événement de type "type1" dont la date de création est supérieure à la date de création de l'événement "type 2"

    Voici ma requête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    select contacts.idcontact
    from contacts 
    left join evenements on contacts.idcontact = evenements.idcontact 
    left join (select idcontact, dateenr from evenements  where type = 'type1' order by dateenr DESC limit 1) as infotop on infotop.idcontact =  contacts.idcontact
    left join (select idcontact,dateenr from evenements  where type = 'type2' order by dateenr DESC limit 1) as ttop on ttop.idcontact=  contacts.idcontact
    where 
    ttop.dateenr < infotop.dateenr 
    group by contacts.idcontact

    La requête fonctionne, sauf qu'elle ne prend pas en compte la notion de contact. Je m'explique. Il suffit qu'un contact ait un événement de type "type2" avec une date la plus récente en base pour que les autres contacts ne s'affichent plus.

    Avez-vous une idée pour m'aider ?

  2. #2
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 193
    Points : 28 077
    Points
    28 077
    Par défaut
    Désolé de t'annoncer, comme tu l'as si bien indiqué dans ton titre, que tes jointures ne sont pas des LEFT JOIN, mais des INNER JOIN.

    C'est l'erreur classique et tellement répandue de mettre dans le filtre des champs provenant des tables jointes. En effet, si tu ne prévois pas dans ce filtre que ton champ puisse aussi être null (c'est le but initial du LEFT JOIN à la base), le filtre ne s'appliquera que sur les enregistrements dont les champs en question sont renseignés, qu'ils soient inclus ou exclus par le filtre, excluant donc les enregistrements où le champ est à null et donc par conséquent transformant implicitement la jointure LEFT JOIN en jointure INNER JOIN.
    --- Sevyc64 ---

    Parce que le partage est notre force, la connaissance sera notre victoire

  3. #3
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    Merci pour ta réponse.
    Tu parles du filtre suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ttop.dateenr < infotop.dateenr
    que je dois transformer en

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (rdvtop.dateenr is not null or rdvtop.dateenr < infotop.dateenr)
    ou des filtres dans les left join ?

  4. #4
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 193
    Points : 28 077
    Points
    28 077
    Par défaut
    Oui, je parlais bien de ttop mais aussi de infotop qui t'est aussi ramené par une jointure gauche.

    Après, il ne suffit pas de rajouter des IS NULL, mais il faut bien réfléchir à ce que la requête va pouvoir ramener comme résultat lorsque les champs (l'un, l'autre, ou les deux) sont nuls et donc que le filtre ne s'applique plus.

    Dans le cas présent, tu peux essayer, mais je pense que le résultat ne te conviendra pas,car à mon avis la requête ne correspond pas au besoin exprimé.


    Reprenons :
    Je cherche à récupérer dans une requête tous les contacts qui ont au moins un événement
    Déjà, allons au plus simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT contacts.idcontact
    FROM contacts 
    INNER JOIN evenements ON contacts.idcontact = evenements.idcontact
    Puisqu'il faut qu'il y est au moins un événement donc un enregistrement dans la table jointe, ça exclut de fait les null. On est bien sur une jointure interne.
    en excluant les contacts qui ont un événement de type "type2"
    Donc bêtement, toujours au plus simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    WHERE evenement.type <> "type2"
    sauf s'il existe un événement de type "type1" dont la date de création est supérieur à la date de création de l'événement "type 2"
    Aie, ici ça se complique.

    Déjà, faisons la différence entre une jointure et un filtre (les filtres se font dans la clause where, et, par pitié, non, on ne met pas les conditions de jointure dans les clause where, n'en déplaise aux profs d'école informatique qui ne vont pas assez sur le terrain).
    Une jointure est faite pour ramener dans le jeu de résultats des champs qui n'appartiennent pas à la table interrogée, mais à une autre table, et ce sous certaines conditions.
    Le filtre, lui, sert à exclure ou à autoriser (et donc implicitement à exclure ce qui n'est pas autorisé) du jeu de résultats certains des enregistrements qui pourraient être ramenés par la requête.

    Dans l'expression sauf s'il existe un événement de type "type1" dont la date de création est supérieur à la date de création de l'événement "type 2", on a est plus à exclure (ou ne pas exclure) des enregistrements, plutôt que d'aller chercher des champs supplémentaires. On peut donc a priori penser que l'on travaille plutôt sur la clause WHERE et non pas sur une jointure.

    On en était donc à
    en excluant les contacts qui ont un événement de type "type2" sauf
    Déjà on peut traduire ça par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    WHERE evenement.type <> "type2" OR (evenement.type = "type2" AND ???????)
    Pour les ??????,
    s'il existe un événement de type "type1" dont la date de création est supérieure à la date de création de l'événement "type 2"
    Ben on va traduire bêtement (en espérant que l'instruction EXISTS existe sous MySQL)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    EXISTS(SELECT * FROM evenement ev2 WHERE ev2.idcontact=contacts.idcontact AND ev2.type="type1" AND ev2.datecrea > evenement.datecrea)
    Donc ici, pour un éventuel enregistrement dont l’événement est de type 2, on vient donc rechercher dans la table evenement, s'il existe des enregistrements, correspondant au même contact, étant de type 1, dont la date de création est supérieure à notre événement de type 2. Je pense que l'on remplit la condition.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT contacts.idcontact
    FROM contacts 
    INNER JOIN evenements ON contacts.idcontact = evenements.idcontact
    WHERE evenement.type <> "type2" OR (evenement.type = "type2" AND EXISTS(SELECT * FROM evenement ev2 WHERE ev2.idcontact=contacts.idcontact AND ev2.type="type1" AND ev2.datecrea > evenement.datecrea))
    En espérant ne pas avoir fait d'erreur.

    EDIT : J'avais bien fait une erreur sur la jointure, la malédiction du copier/coller
    --- Sevyc64 ---

    Parce que le partage est notre force, la connaissance sera notre victoire

  5. #5
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    Whoua ! Sacrée explication !

    Merci d'avoir pris le temps de m'expliquer clairement. Je vais laisser de côté ce sujet le temps du week end pour le remettre en place lundi matin. Avec les idées claires et tes explications cela devrait être plus simple.

    Je viendrai mettre à jour le post afin de venir donner un explication finale.

    EXISTS exist sur mysql ;-)

Discussions similaires

  1. SQL INNER JOIN et SELECT
    Par onha94 dans le forum Développement
    Réponses: 8
    Dernier message: 22/01/2015, 17h32
  2. Réponses: 2
    Dernier message: 21/05/2012, 11h08
  3. SQL inner join select temps d'éxécution
    Par binouzzz19 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 23/10/2007, 14h50
  4. Un doute...select avec INNER JOIN
    Par Thierry8 dans le forum Requêtes
    Réponses: 6
    Dernier message: 18/12/2005, 16h14
  5. Inner Join & Select
    Par bakaneko dans le forum Langage SQL
    Réponses: 7
    Dernier message: 10/02/2004, 10h48

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