Mysql
 sql >> Database >  >> RDS >> Mysql

Cerca post e tag nella stessa query

È meglio se non scegli un group_concat soluzione perché non è affidabile a causa della lunghezza del carattere, ha un limite predefinito di 1024 caratteri da concatenare ma può essere aumentato come definito in manuale ma non puoi fare affidamento completamente sul limite definito, invece puoi gestirlo nel tuo livello di applicazione (php) come se stessi recuperando dati e da qualche parte in cui desideri visualizzare i post e i relativi tag puoi ancora utilizzare la tua query di partecipazione con l'ordine per post ora ogni post può avere più di un tag, quindi il set di risultati avrà dati di post duplicati poiché ogni riga di post avrà un tag e un'altra riga con lo stesso post avrà un secondo tag e così via ora quando scorri i risultati visualizza ogni post solo una volta per aggiungendo qualche assegno

$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();

Nella query precedente ho aggiunto t.* per selezionare tutti i post e i relativi tag ora in loop $currentParent avrà un ID post precedente nel ciclo controlla se è lo stesso post quindi visualizza i suoi tag se la condizione restituisce false quindi è un nuovo post mostra l'intestazione del post usando il markup (h1), ho selezionato tutte le colonne da entrambe le tabelle ma dovresti aggiungere solo ciò che serve colonne dalla tabella dei tag e se post e tabella dei tag hanno colonne con lo stesso nome, nella query li definisci con alias diversi

$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>'; 
    ...
}

Il markup risultante sarà come

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

Se non stai visualizzando i dati e li stai utilizzando da qualche altra parte (servizio web), usa comunque una query unita e trasforma i tuoi dati creando array/oggetto ogni post ha una matrice dei suoi tag correlati qualcosa come di seguito

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

c'è un altro modo che è altamente sconsigliato ottieni post e in loop ottieni tag eseguendo query ora questa soluzione funzionerà ma comporterà query indesiderate in modo che venga eseguita una query aggiuntiva per ogni post.

Ora, se vuoi davvero restare con group_concat approccio per rispondere alla tua domanda I'm not sure if I can trust the order? c'è anche un modo per aggiungere order by in group_concat in modo che i tag concatenati risultanti vengano ordinati e per la seconda colonna puoi inserire gli stessi criteri di ordinamento

$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');