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

Selecionar em um relacionamento muitos para muitos no MySQL


Existem duas maneiras de fazer isso. Eu prefiro a primeira maneira, que é auto-juntar para cada tag:
SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a1 ON a1.LocationID = l.ID
JOIN Tags t1 ON a1.TagID = t1.ID AND t1.Name = ?
JOIN LocationsTagsAssoc a2 ON a2.LocationID = l.ID
JOIN Tags t2 ON a2.TagID = t2.ID AND t2.Name = ?
JOIN LocationsTagsAssoc a3 ON a3.LocationID = l.ID
JOIN Tags t3 ON a3.TagID = t3.ID AND t3.Name = ?;

A outra maneira também funciona, mas usando GROUP BY no MySQL tende a incorrer em uma tabela temporária e o desempenho é lento:
SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a ON a.LocationID = l.ID
JOIN Tags t ON a.TagID = t.ID
WHERE t.Name IN (?, ?, ?)
GROUP BY l.ID
HAVING COUNT(*) = 3;

Comentário de @Erikoenig:

Se você quiser ter certeza de que não há tags extras, você pode fazer desta forma:
SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a ON a.LocationID = l.ID
JOIN Tags t ON a.TagID = t.ID
GROUP BY l.ID
HAVING COUNT(*) = 3 AND SUM(t.Name IN (?, ?, ?)) = 3;

Retirar a cláusula WHERE permite que outras tags sejam contadas, se houver. Portanto, COUNT() pode ser maior que 3.

Ou se a contagem for exatamente três tags, mas algumas dessas três não forem as tags corretas, a condição SUM() na cláusula HAVING garante que todas as três tags desejadas estejam presentes no grupo.