How do you do this in mysql or rails
-
20-02-2021 - |
Question
Say you have a posts table and a tags table, and both are related by a post_tags table.
so
posts has id/subject/body columns
tags has id/name
post_tags has id/post_id/tag_id
in rails terminology, I have a Post Model that has many Tags through AssetTags.
I'm trying to query for a post that has 2 specific tags. so if there is a rails tag and a mysql tag, I want a query that returns a post that only has those two tags.
make sense?
Any way to do this with activerecord (I'm using search logic) or mysql?
Solution
This SQL returns the posts that contain both tags.
select
p.*
from
posts p
,asset_tags atg1
,asset_tags atg2
,tags t1
,tags t2
where
p.id = atg1.post_id
and t1.id = atg1.tag_id
and t1.tag = 'MySQL'
and p.id = atg2.post_id
and t2.id = atg2.tag_id
and t2.tag = 'Rails'
;
As for doing it via Active record, an alternative would be to query for each of the tags and then & the resulting arrays to get the intersection of the two.
OTHER TIPS
For mysql, sure, you can get the data
SELECT p.*
FROM posts p
JOIN post_tags pt
ON p.post_id = pt.post_id
WHERE pt.tag_id in (tagId1, tagId2)
I have not used Rails ActiveRecord but I imagine it would be something along the lines of
get('posts');
join('post_tags','post_id');
where_in('tag_id', array(tagId1, tagId2);
execute();
Given these models:
def Post
has_many :asset_tags
has_many :tags, :through => :asset_tags
end
def AssetTag
has_one :post
has_one :tag
end
def Tag
has_many :asset_tags
has_many :posts, :through => :asset_tags
end
You can do this:
Post.joins(:asset_tags => :tag).where(
"tags.name in ('?', '?')", 'foo', 'bar' )
Now, this actually doesn't do anything with the has_many :through
association -- I'm not sure if there's an even slicker api provided that utilizes that.
John Bachir's answer can be modified to...
Post.joins(:asset_tags => :tag)
.where("tags.name in ('?')", 'foo')
.where("tags.name in ('?')", 'bar')