问题
Been trying to reintroduce myself to SQL through some practice questions I've developed for myself, but struggling to find a better way of approaching the following problem:
playlists
id title
1 Title1
2 Title2
playlist_clips
id playlist_id clip_id
1 Title1 3
2 Title2 1
playlist_tags
playlist_id tag_id
1 1
1 2
2 2
Clips and Tags are two entirely separate tables, and I am using the playlist_tags and playlist_clips to connect them to the playlists table, to represent the two-way one-to-many relationships.
I wanted to select all the playlists that have a given title, and have ALL of the tags provided in the query (in this example [1, 2]), not just "at least one of them".
This is what I've come up with:
select p_clips.* from
(
select p.id, p.title, count(pc.id) as number_of_clips
from playlists p
left join playlist_clips pc on p.id = pc.playlist_id
where p.title like "Test1"
group by id
) as p_clips
inner join
(
select *
from playlists p
left join playlist_tags pt on p.id = pt.playlist_id
where pt.tag_id in (1, 2)
group by id
having count(*) = 2
) as p_tags
on p_clips.id = p_tags.id
Whilst, from my testing I've found this to work, it doesn't look particularly elegant, and I also assume it's not terribly efficient performance-wise. (I've removed irrelevant parameters from the code for this example, such as select parameters.)
What would be a cleaner way of approaching this, or at the least, a more optimized approach?
Expected Result:
id title
260 Title1
EDIT: I apologize for my initial confusing post, I've tried to clean up my tables and the information they contain.
回答1:
I wanted to select all the playlists that have a given title, and have ALL of the tags provided in the query (in this example [1, 2]), not just "at least one of them".
You don't need the clips table at all. You don't need left joins or the playlists table in the subquery.
That suggests:
select p.*
from playlists p join
(select pt.playlist_id
from playlist_tags pt
where pt.tag_id in (1, 2)
group by id
having count(*) = 2
) pt
on p.id = pt.playlist_id
where p.title like 'Test1';
You could phrase this without a subquery as well:
select p.*
from playlists p join
playlist_tags pt
on p.id = pt.id
where p.title like 'Test1' and
pt.tag_id in (1, 2)
group by p.id
having count(*) = 2
来源:https://stackoverflow.com/questions/59018101/cleaning-up-sql-query-with-nested-query-and-inner-join