[MySQL] Requete avec JOIN : infos dans des bases différentes

Requete avec JOIN : infos dans des bases différentes [MySQL] - SQL/NoSQL - Programmation

Marsh Posté le 21-07-2009 à 01:54:23    

Bonjour,
 
J'ai une table contenant des objets ayant chacun un id.
 

space_map
 
x  y  type  id
--------------
0  5  1      6
1 17  3      9
etc...  


 
Chaque enregistrement est soit une étoile, soit une planète, soit un astéroïde selon le champs 'type' (1:etoile, 2:planete, 3:asteroide).
Avec un JOIN, je voudrais chercher l'image de l'objet. Cette image est stockée dans le champs 'map_image' de la table lui correspondant.
En effet, il y a 3 tables 'etoile', 'planete' et 'asteroide'.
 
Par exemple pour l'étoile :
 

etoile
 
id     map_image     etc...
---------------------------
 6   etoile1.png
etc...


Ces 3 tables sont complètement différentes mais ont en commun les champs id et map_image.
Donc je voudrais que selon le type de l'enregistrement, on aille chercher l'image qui correspond dans la table appropriée.
 
Ca n'a pas l'air très complexe, c'est pourquoi j'ai pensé pouvoir le faire en une seule requète, mais je suis bloqué.
Voila ce que j'ai actuellement :
 

Code :
  1. SELECT space_map.* , etoile.map_image, planete.map_image, asteroide.map_image,
  2. FROM space_map
  3. INNER  JOIN etoile ON ( space_map.type =1 AND space_map.id = etoile.id )
  4. INNER  JOIN planete ON ( space_map.type =2 AND space_map.id = planete.id )
  5. INNER  JOIN asteroide ON ( space_map.type =3 AND space_map.id = asteroide.id )
  6. WHERE space_map.x >0
  7. AND space_map.x <20
  8. AND space_map.y >0
  9. AND space_map.y <20


Mais ca ne fonctionne évidement pas, puisqu'il ne sait pas comment chercher les 2 autres map_image....
 
Existe-t-il un JOIN spécial qui répondrait à mes attentes ?
 
Merci de votre attention  :hello:


Message édité par Pascal le nain le 21-07-2009 à 01:59:14
Reply

Marsh Posté le 21-07-2009 à 01:54:23   

Reply

Marsh Posté le 21-07-2009 à 10:58:06    

Un ami m'a proposé ca :
 

Code :
  1. SELECT space_map.* , etoile.map_image, planete.map_image, asteroide.map_image,
  2. FROM space_map
  3. INNER  JOIN etoile ON (space_map.id = etoile.id )
  4. INNER  JOIN planete ON (space_map.id = planete.id )
  5. INNER  JOIN asteroide ON ( space_map.id = asteroide.id )
  6. WHERE space_map.x >0
  7. AND space_map.x <20
  8. AND space_map.y >0
  9. AND space_map.y <20


 
Et à ce moment là, sql nous retourne les 3 images correspondantes à l'id dans chaque type (à condition que l'id existe).
Il suffit alors de choisir l'image entre les 3 en fonction du type retourné.
 
Ce n'est pas une mauvaise idée, mais au niveau performance, il doit y avoir mieux à faire. En effet, sql me retourne 2 strings pour rien.
Or c'est une requete que je vais faire très fréquemment. Je souhaite donc l'optimiser un max.
 
Petit up  :hello:

Reply

Marsh Posté le 21-07-2009 à 17:15:15    

Code :
  1. SELECT
  2.   space_map.*,
  3.   coalesce(etoile.map_image,planete.map_image,asteroide.map_image) map_image
  4. FROM space_map
  5. left  JOIN etoile ON space_map.id = etoile.id
  6. left  JOIN planete ON space_map.id = planete.id
  7. left  JOIN asteroide ON pace_map.id = asteroide.id
  8. WHERE space_map.x >0
  9. AND space_map.x <20
  10. AND space_map.y <20


 
je sais pas à quoi correspond ta clause where donc je l'ai laissée

Reply

Marsh Posté le 21-07-2009 à 17:52:01    

Bien essayé ;)
 
Mais coalesce retourne le premier non nul.
Or il peut très bien avoir une étoile et une planete qui ont le même id.
L'astre est identifié, non pas juste par un id, mais par son type ET son id au sein de son type :)
 
Si vraiment rien n'est faisable, je donnerai effectivement un identifiant unique à tous les astres tel qu'il n'y aura pas de collisions.
 
Pour la clause where, c'est juste un genre de champs de vision. Chaque astre est visible si on le regarde. Le champs de vision est pour l'instant un carré de 20x20. Mais ca n'influe pas sur la requete ;)

Reply

Marsh Posté le 21-07-2009 à 18:09:53    

et en remettant le type = X dans les jointures ?


Message édité par tet2neu le 21-07-2009 à 18:10:10
Reply

Marsh Posté le 21-07-2009 à 18:18:46    

J'essaye ca ce soir ;)
 
Sinon une petite question toute autre, je cherche à récupérer la valeur de l'index (la clé primaire) d'une table. J'ai d'abord pensé à un SELECT MAX(id), mais on n'est pas à l'abri d'une suppression du dernière enregistrement. J'ai ensuite cherché du coté des fonctions php, mais aucune ne semble remplir cette fonction...

Reply

Marsh Posté le 21-07-2009 à 18:49:14    

c'est un auto increment ?
je crois que la fonction mysql_insert_id (ou truc comme ça) renvoie le dernier id inséré ;)

Reply

Marsh Posté le 21-07-2009 à 19:50:45    

Oui il est possible d'avoir l'id à l'insertion. Mais je souhaite le récupérer n'importe quand. Bizarre que personne n'y ait pensé...  :sweat:  
Je ne vais quand même pas insérer puis supprimer juste pour avoir l'id, ce serait ridicule...

Reply

Marsh Posté le 21-07-2009 à 20:00:54    

Voila j'ai testé
 

SELECT space_map.*, COALESCE(etoile.map_image, planete.map_image, asteroide.map_image)  
FROM space_map  
INNER JOIN etoile ON (space_map.type=1 AND space_map.id=etoile.id)  
INNER JOIN planete ON (space_map.type=2 AND space_map.id=planete.id)  
INNER JOIN asteroide ON (space_map.type=3 AND space_map.id=asteroide.id)


En ayant viré le WHERE.
 
Il n'y a plus d'erreur SQL, mais sql ne renvoie aucun enregistrement...
Pourtant il me semble que l'on ne filtre rien...

Reply

Marsh Posté le 21-07-2009 à 20:05:43    

c'est normal que ça ne renvoie rien, il faut du left join et pas du inner join ;)

 

en gros, avec le inner, tu lui demande de renvoyer tous les objets qui sont à la fois une étoile, une planète et un astéroïde. Et j'imagine que tu n'en as pas :)


Message édité par tet2neu le 21-07-2009 à 20:06:57
Reply

Marsh Posté le 21-07-2009 à 20:05:43   

Reply

Marsh Posté le 21-07-2009 à 20:07:10    

Désolé pour ce triple post :)
 
En effet, ca fonctionne nickel avec un LEFT JOIN qui lui n'exclut personne en cas d'absence.
Voila le code final :
 

SELECT space_map.*,  
       COALESCE(etoile.map_image, planete.map_image, asteroide.map_image) AS image  
FROM space_map
LEFT JOIN etoile    ON (space_map.type=1 AND space_map.id=etoile.id)
LEFT JOIN planete   ON (space_map.type=2 AND space_map.id=planete.id)    
LEFT JOIN asteroide ON (space_map.type=3 AND space_map.id=asteroide.id)
WHERE  space_map.x>0  
  AND space_map.x<20  
  AND space_map.y>0      
  AND space_map.y<20


 
Merci beaucoup pour ton aide  :hello:


Message édité par Pascal le nain le 21-07-2009 à 20:08:19
Reply

Marsh Posté le 21-07-2009 à 20:08:11    

de rien ;)

Reply

Marsh Posté le 22-07-2009 à 16:39:34    

Encore une petite question.
C'est une requete que je dois exécuter très souvent, il faut donc que je l'optimise un max.
 
J'ai lu ici http://sqlpro.developpez.com/cours/optimiser/ (partie 9, ligne 12 du tableau) que faire un paquet de UNION est plus rapide qu'un paquet de INNER + coalesce().
 
Qu'en penses-tu ?

Reply

Marsh Posté le 22-07-2009 à 17:17:52    

j'en pense que dans ton cas l'union n'est pas la solution la plus performante.
Dans le lien que tu donnes, le point numéro 12 conseille bien de transformer les COALESCE en UNION, mais l'exemple donné se justifie car les données viennent toutes de la même table.
Si tu regardes le point numéro 16, ils conseillent de transformer les UNION en jointures, et l'exemple donné utilise des.... COALESCE !

 

Donc je dirais : reste comme ça ;)

 

D'ailleurs ils oublient un conseil important : préférer "UNION ALL" à "UNION" quand cela est possible


Message édité par tet2neu le 22-07-2009 à 17:19:26
Reply

Sujets relatifs:

Leave a Replay

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