TTBDV
TTBDV

Reputation: 65

Cleaning up SQL query with nested query and inner join

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.

Upvotes: 0

Views: 88

Answers (1)

Gordon Linoff
Gordon Linoff

Reputation: 1270391

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

Upvotes: 1

Related Questions