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

Hai bisogno di aiuto con la query sql per trovare le cose contrassegnate con tutti i tag specificati

Utilizzo di IN:

SELECT p.*
  FROM POSTS p
 WHERE p.id IN (SELECT tg.post_id
                  FROM TAGGINGS tg
                  JOIN TAGS t ON t.id = tg.tag_id
                 WHERE t.name IN ('Cheese','Wine','Paris','Frace','City','Scenic','Art')
              GROUP BY tg.post_id
                HAVING COUNT(DISTINCT t.name) = 7)

Utilizzo di un JOIN

SELECT p.*
  FROM POSTS p
  JOIN (SELECT tg.post_id
          FROM TAGGINGS tg
          JOIN TAGS t ON t.id = tg.tag_id
         WHERE t.name IN ('Cheese','Wine','Paris','Frace','City','Scenic','Art')
      GROUP BY tg.post_id
        HAVING COUNT(DISTINCT t.name) = 7) x ON x.post_id = p.id

Utilizzo di EXISTS

SELECT p.*
  FROM POSTS p
 WHERE EXISTS (SELECT NULL
                 FROM TAGGINGS tg
                 JOIN TAGS t ON t.id = tg.tag_id
                WHERE t.name IN ('Cheese','Wine','Paris','Frace','City','Scenic','Art')
                  AND tg.post_id = p.id
             GROUP BY tg.post_id
               HAVING COUNT(DISTINCT t.name) = 7)

Spiegazione

Il punto cruciale è che il COUNT(DISTINCT t.name) deve corrispondere al numero di nomi di tag per garantire che tutti quei tag siano correlati al post. Senza DISTINCT, c'è il rischio che i duplicati di uno dei nomi possano restituire un conteggio di 7, quindi avresti un falso positivo.

Prestazioni

La maggior parte ti dirà che JOIN è ottimale, ma i JOIN rischiano anche di duplicare le righe nel set di risultati. EXISTS sarebbe la mia prossima scelta:nessun rischio duplicato e un'esecuzione generalmente più rapida, ma controllando il piano di spiegazione alla fine ti dirà cosa è meglio in base alla tua configurazione e ai tuoi dati.