Mysql
 sql >> Base de données >  >> RDS >> Mysql

Requête pour la publication et les balises dans la même requête

C'est mieux si vous n'optez pas pour un group_concat solution car elle n'est pas fiable en raison de la longueur des caractères, elle a une limite par défaut de 1024 caractères à concaténer mais elle peut être augmentée, ce qui est défini dans manuel mais vous ne pouvez pas entièrement vous fier à la limite définie, vous pouvez la gérer dans votre couche d'application (php) comme si vous récupérez des données et quelque part où vous souhaitez afficher les publications et ses balises associées, vous pouvez toujours utiliser votre requête de jointure avec l'ordre des publications maintenant chaque publication peut avoir plus d'une balise, de sorte que le jeu de résultats aura des données de publication en double car chaque ligne de publication aura une balise et une autre ligne avec la même publication aura une deuxième balise et ainsi de suite maintenant, lorsque vous parcourez vos résultats, affichez chaque publication une seule fois par ajouter un chèque

$this->db->select('p.*,t.*');
$this->db->from('posts p');
$this->db->join('tags_map tm', 't.id_post = p.id');
$this->db->join('tags t', 't.id = tm.id_tag');
$this->db->order_by('p.id asc,t.id asc');
$results = $this->db->get();

Dans la requête ci-dessus, j'ai ajouté t.* pour sélectionner tous les messages et ses balises associées maintenant en boucle $currentParent aura un précédent post id en boucle vérifier s'il s'agit du même post puis afficher ses balises si la condition renvoie false alors c'est un nouveau post afficher l'en-tête du post en utilisant le balisage (h1), j'ai sélectionné toutes les colonnes des deux tables mais vous ne devez ajouter que ce qui est nécessaire les colonnes de la table des balises et si la table des publications et des balises ont des colonnes du même nom, alors dans la requête, définissez-les avec un alias différent

$currentParent = false;
foreach ($results as $post) {
    if ($currentParent != $post->id) {
        echo '<h1>' . $post->title . '</h1>';
        $currentParent = $post->id;
    }
    echo '<p>' . $post->name . '</p>'; /** here list tags info*/
    echo '<p>' . $post->tag_other_details . '</p>'; 
    ...
}

Le balisage résultant ressemblera à

<h1>Post title 1</h1>
    <p>tag 1</p>
    <p>tag 2</p>
<h1>Post title 2</h1>
    <p>tag 3</p>...

Si vous n'affichez pas de données et que vous les utilisez ailleurs (service Web), utilisez toujours une requête jointe et transformez vos données en créant un tableau/objet, chaque publication a un tableau de ses balises associées, comme ci-dessous

$posts =array();
foreach ($results as $post) {
 $posts[$post->id]['title'] = $post->title;
 $posts[$post->id]['tags'][] =array('id' => $tag->id ,'name' =>$post->name);
}

il existe un autre moyen qui est fortement déconseillé obtenir des messages et en boucle obtenir des balises en exécutant la requête maintenant cette solution fonctionnera mais impliquera des requêtes indésirables afin qu'il y ait une requête supplémentaire exécutée pour chaque message.

Maintenant, si vous voulez vraiment vous en tenir à group_concat approche pour répondre à votre question I'm not sure if I can trust the order? il existe également un moyen d'ajouter order by dans group_concat de sorte que les balises concaténées résultantes seront triées et pour la deuxième colonne, vous pouvez mettre les mêmes critères de tri

$this->db->select('p.*,group_concat(t.name order by t.id) as thetags,
                       group_concat(t.relevance order by t.id) as therelevances');
$this->db->from('posts p');
$this->db->join('tags_map tm', 't.id_post = p.id');
$this->db->join('tags t', 't.id = tm.id_tag');
$this->db->group_by('p.id');