Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Precisa de ajuda com a consulta sql para encontrar coisas marcadas com todas as tags especificadas

Usando 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)

Usando um 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

Usando 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)

Explicação


O cerne das coisas é que o COUNT(DISTINCT t.name) precisa corresponder ao número de nomes de tags para garantir que todas essas tags estejam relacionadas à postagem. Sem o DISTINCT, existe o risco de que duplicatas de um dos nomes retornem uma contagem de 7, então você teria um falso positivo.

Desempenho


A maioria dirá que o JOIN é ideal, mas os JOINs também correm o risco de duplicar linhas no conjunto de resultados. EXISTS seria minha próxima escolha - sem risco duplicado e execução geralmente mais rápida, mas verificar o plano de explicação acabará dizendo o que é melhor com base em sua configuração e dados.