2010-02-21 9 views
3

J'ai deux tables (entrées et balises) avec une table de liaison many-to-many. En ce moment, je fais une requête pour récupérer toutes les entrées qui répondent à mes critères, et une requête pour chaque entrée pour récupérer les balises.Requête MySQL multi-niveaux?

Y aurait-il un moyen de dire, avoir les balises retournées par une nouvelle colonne en tant que tableau dans la première requête?

Répondre

1

Cette requête:

SELECT  e.id        entry_id 
,   GROUP_CONCAT(t.txt ORDER BY t.txt) tags 
FROM  entry e 
LEFT JOIN entry_tag et 
ON   e.id = et.entry_id 
LEFT JOIN tag t 
ON   et.tag_id = t.id 
GROUP BY e.id 

renverra les balises comme une liste séparée par des virgules. Vous pouvez lire sur GROUP_CONCAT pour plus d'options: http://dev.mysql.com/doc/refman/5.1/en/group-by-functions.html#function_group-concat

Dans votre application, vous devriez être en mesure de l'étendre assez facilement. Par exemple en php, vous pouvez utiliser explode: http://php.net/manual/en/function.explode.php

Si vous avez besoin d'autres attributs des tag ou entry_tag tables, vous pouvez ajouter encore plus GROUP_CONCAT colonnes, ou penser à un format de sérialisation pour vos données (comme JSON) et utiliser GROUP_CONCAT à ce sujet, ou vous pouvez simplement renvoyer plusieurs lignes par entrée et traiter les résultats dans l'application de garder les étiquettes ainsi que des entrées:

$sql = ' 
    SELECT  e.id     entry_id 
    ,   t.id     tag_id 
    ,   t.txt     tag_text 
    ,   t.published   tag_published 
    FROM  entry e 
    LEFT JOIN entry_tag et 
    ON   e.id = et.entry_id 
    LEFT JOIN tag t 
    ON   et.tag_id = t.id 
    ORDER BY e.id 
';   
$result = mysql_query($ql); 
$entry_id = NULL; 
$entry_rows = NULL; 
while ($row = mysql_fetch_assoc($result)) { 
    if ($entry_id != $row['entry_id']) { 
     if (isset($entry_id)) {   //ok, found new entry 
      process_entry($entry_rows); //process the rows collected so far 
     } 
     $entry_id = $row['entry_id']; 
     $entry_rows = array(); 
    } 
    $entry_rows[] = $row;     //store row for his entry for later processing 
} 
if (isset($entry_id)){     //process the batch of rows for the last entry 
    process_entry($entry_rows);   
} 
+2

Soyez conscient que group_concat a une limite, vous devez 'SET group_concat_max_len = 2048; "au début pour s'assurer que GROUP_CONCAT accueille les nombreux champs. – Pentium10

+0

@ Pentium10: c'est un moyen. Un autre moyen est de le spécifier dans votre my.cnf. Votre taille de 2048 semble cependant arbitraire. Personnellement, je recommande de le mettre à @@ max_allowed_packet si vous voulez être vraiment sûr. –

+0

Nous avons beaucoup de tags, et ce 2048 fonctionnait très bien. Merci d'avoir partagé cette variable. – Pentium10