SELECT * FROM post
WHERE id IN
(
select post_id from post_tags
INNER JOIN tags ON post_tag.tag_id = tag.id
WHERE tag.tag in ("foo","bar","baz")
GROUP BY post_id
HAVING COUNT(*) = 3
)
AND author IN ("Joe","Jane")
ORDER BY post_date DESC;
Of course normalizing tags is silly as they are natural keys so it should be as you first stated: SELECT * FROM post
WHERE id IN
(
select post_id from post_tags
WHERE tag in ("foo","bar","baz")
GROUP BY post_id
HAVING COUNT(*) = 3
)
AND author IN ("Joe","Jane")
ORDER BY post_date DESC;Are subselects still ridiculously inefficient in MySQL? It's been a long while since I've used them. I do like how those queries read, though.
Sorry I only use proper DB's like PostgreSQL and MSSQL who optimizer's have no problems with this ;).
Also what I like about the count approach is you can do "show me all the posts with at least 2 out of the 3 tags matching" fuzzier search if you desire.
I'm not sure what you mean, but the parent's SQL is valid and returns the same data as the gp's, only in a more efficient manner. No need to do three inner joins when you can get away with one.
In fact, you can take out the second part of the inner join condition and move it in the where clause, like this (execution plan will stay the same):
SELECT posts.* FROM posts
INNER JOIN post_tags pt ON pt.post_id = posts.id
WHERE posts.author IN ('Joe', 'Jane') AND pt.tag IN ('foo', 'bar', 'baz')
ORDER BY post_date DESC;
It's worth noting that I threw the SQL query a bone by denormalizing post_tags into one table. In a properly relational DB, you'd have a tags table, a posts table, and a post_tags join table, so the query gets even hairier (or you have to do two queries).
Yikes.It's also worth noting that this generates a massive temp table to be sorted, which is very likely going to end up causing you to have to do a filesort. In practice, you'd probably break this down into 3 queries (forgive my mixing languages):
Easily doable in both languages, but Mongo's denormalized structure makes this sort of use case a ton simpler.