[resolu]Besoin d'aide pour jointure sur mySQL

Besoin d'aide pour jointure sur mySQL [resolu] - SQL/NoSQL - Programmation

Marsh Posté le 08-10-2007 à 15:44:00    

Bonjour à tous,
 
Je vais essayer de décrire mon probleme:
J'ai une table 'objets', qui possede deux colonnes : id et description.
J'ai  une table users,qui possede aussi deux colonnes: id et name.
Enfin,j'ai une table historique, qui possede 4 colonnes: id_user, id_objet, type_action et date.
Cette derniere table va enfait enregistrer les actions des utilisateurs sur les objets, sachant qu'il y a différents types d'actions, représentés par des nombres.
Pour chaque action, on enregistre donc l'id de l'utilisateur,l'id de l'objet, la date et le type de l'action.
 
Je voudrais récupérer la liste de tous les objets, avec pour chaque objet, le nom de l'utilisateur qui a effectué l'action de type N sur cet objet.
Là ou ca se corse, c'est que l'action N peut avoir été effectuée plusieurs fois, et par des utilisateurs différents (je précise que l'action N a été effectuée au moins une fois), et je voudrais récupérer le premier utilisateur ayant effectué l'action (premier au sens temporel).
Voici mes différents essais:

Code :
  1. SELECT o.id,o.description,h.date,u.name
  2. FROM objets AS o,
  3. INNER JOIN (SELECT id_user,id_objet FROM historique WHERE type_action=N) h
  4. ON h.id_objet=o.id
  5. INNER JOIN users AS u
  6. ON u.id=h.id_user


 
->Probleme: retourne des doublons quand plusieurs utilisateurs ont effectué l'action N sur un objet.
Pour corriger ce probleme de doublons, j'ai tenté un truc:

Code :
  1. SELECT o.id,o.description,h.date,u.name
  2. FROM objets AS o,
  3. INNER JOIN (SELECT id_user,id_objet FROM historique WHERE type_action=N LIMIT 1) h
  4. ON h.id_objet=o.id
  5. INNER JOIN users AS u
  6. ON u.id=h.id_user


->Apres m'etre demandé pourquoi cette requete ne retournait rien, je me suis vite rendu compte que j'avais fait n'importe quoi avec mon "LIMIT", et que c'était normal.
 
 
En dernier recours, je suppose que je pourrais post-filtrer le resultat de la requete 1 avec PHP, mais l'idée ne me plait pas beacoup...
Je pense qu'il doit y avoir moyen de faire faire ca à mySQL, mais ca me dépasse un peu.
 
Des idées?
 
Merci et bonne journée :)


Message édité par Halike le 09-10-2007 à 12:39:09
Reply

Marsh Posté le 08-10-2007 à 15:44:00   

Reply

Marsh Posté le 08-10-2007 à 22:15:03    

On va être méthodique :
- 1ère sous-requête qui récupère pour chaque id_objet la date min pour l'action recherchée (on va dire que c'est la 123), qu'on va appeller tb_A dans la requête
- jointure vers la table historique pour récupérer l'id de l'utilisateur
- jointure vers la table users pour récupérer son nom
- jointure vers la table objets pour récupérer son nom
 
Et pour le cas où il n'y aurait pas d'action effectuée, on protège les champs correspondants par un IFNULL
 
C'est parti :o  
 
SELECT objets.name, IFNULL(tb_A.dmin, '0000-00-00') date, IFNULL(users.name, '') user_name
FROM
  (SELECT id_objet, min(date) dmin
  FROM historique
  WHERE type_action=123
  GROUP BY id_objet) tb_A
LEFT JOIN historique ON tb_A.id_objet=historique.id_objet AND tb_A.dmin=historique.date
LEFT JOIN users ON historique.id_user=users.id
LEFT JOIN objets ON tb_A.id_objet=objets.id
 
Aux fautes prêts, je pense que ca devrait renvoyer un résultat pas trop éloigné de ce que tu recherches [:figti]  
 
(mais je suis étonné de ne pas trouver plus simple :??: )


Message édité par mrbebert le 08-10-2007 à 22:16:22
Reply

Marsh Posté le 09-10-2007 à 12:38:33    

Yes! :)
Merci beaucoup, ca fonctionne.
J'ai fait un truc de ce style:
SELECT o.id,o.description,u.name,h.date
FROM (SELECT id_objet,id_user,MIN(date) FROM historique WHERE type_action=123 GROUP BY id_objet) h
INNER JOIN users u ON u.id=h.id_user
INNER JOIN objets o ON o.id=h.id_objet

 
Ca semble fonctionner.
 
Encore Merci.
 
Bonne journée :)
 
Edit: Voir message en dessous...


Message édité par Halike le 09-10-2007 à 15:02:28
Reply

Marsh Posté le 09-10-2007 à 13:01:23    

FAUX !!!!!!!!!!!!!!!!!! :D  
 
Quand tu mets :
SELECT id_objet, id_user, MIN(date) FROM historique ...
Qu'est-ce qui te garantit que le id_user qui est fourni est bien celui qui correspond à la date minimale ?
 
(réponse : rien :o  [:proy] )

Reply

Marsh Posté le 09-10-2007 à 15:06:17    

:ange:  
Arf. Mais bien sur.
 
Il aurait été marrant à débugger celui la...
Du coup, re-merci, et re-résolu :)

Reply

Marsh Posté le 09-10-2007 à 17:47:08    

FROM objets AS o,
=> vire la ","
 
pour le reste pas lu le topic.
je suis tout naze.
 
on a le droit de faire une jointure sur un sous-select.
par contre je vois pas trop l'intérêt dans ton cas, je suis pas sûr que ton limit apporte quand chose niveau perfs.
rien que pour la lisibilité, tu ferais mieux de faire une belle jointure régulière.


Message édité par MagicBuzz le 09-10-2007 à 17:47:27
Reply

Marsh Posté le 09-10-2007 à 17:49:34    

mrbebert a écrit :

FAUX !!!!!!!!!!!!!!!!!! :D  
 
Quand tu mets :
SELECT id_objet, id_user, MIN(date) FROM historique ...
Qu'est-ce qui te garantit que le id_user qui est fourni est bien celui qui correspond à la date minimale ?
 
(réponse : rien :o  [:proy] )


heink ?
 
en toute logique, le id_user qui se trouve sur la même ligne que ta date, correspond forcément, car le id_user DOIT est dans le group by.
 
après, mysql permet de faire n'importe quoi, et se torche avec les 20000 pages de la norme SQL. c'est pas pour autant qu'il faut exploiter ses bugs et prendre pour acquis son comportement incohérent.

Reply

Marsh Posté le 09-10-2007 à 17:50:58    

oublié mon poste d'avant le précédent.
à priori 100% à côté de la plaque.
 
l'hiver arrive, il est grand temps pour moi d'hiberner :o

Reply

Marsh Posté le 09-10-2007 à 21:36:36    

MagicBuzz a écrit :


heink ?
 
en toute logique, le id_user qui se trouve sur la même ligne que ta date, correspond forcément, car le id_user DOIT est dans le group by.
 
après, mysql permet de faire n'importe quoi, et se torche avec les 20000 pages de la norme SQL. c'est pas pour autant qu'il faut exploiter ses bugs et prendre pour acquis son comportement incohérent.

Justement, il n'y est pas (et  n'a pas à y être dans ce cas).
Donc on est d'accord :o  

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed