How to filter SQL results in a has-many-through relation

后端 未结 13 1487
有刺的猬
有刺的猬 2020-11-21 05:17

Assuming I have the tables student, club, and student_club:

student {
    id
    name
}
club {
    id
    name
}
stude         


        
13条回答
  •  眼角桃花
    2020-11-21 06:01

    Since noone has added this (classic) version:

    SELECT s.*
    FROM student AS s
    WHERE NOT EXISTS
          ( SELECT *
            FROM club AS c 
            WHERE c.id IN (30, 50)
              AND NOT EXISTS
                  ( SELECT *
                    FROM student_club AS sc 
                    WHERE sc.student_id = s.id
                      AND sc.club_id = c.id  
                  )
          )
    

    or similar:

    SELECT s.*
    FROM student AS s
    WHERE NOT EXISTS
          ( SELECT *
            FROM
              ( SELECT 30 AS club_id  
              UNION ALL
                SELECT 50
              ) AS c
            WHERE NOT EXISTS
                  ( SELECT *
                    FROM student_club AS sc 
                    WHERE sc.student_id = s.id
                      AND sc.club_id = c.club_id  
                  )
          )
    

    One more try with a slightly different approach. Inspired by an article in Explain Extended: Multiple attributes in a EAV table: GROUP BY vs. NOT EXISTS:

    SELECT s.*
    FROM student_club AS sc
      JOIN student AS s
        ON s.student_id = sc.student_id
    WHERE sc.club_id = 50                      --- one option here
      AND NOT EXISTS
          ( SELECT *
            FROM
              ( SELECT 30 AS club_id           --- all the rest in here
                                               --- as in previous query
              ) AS c
            WHERE NOT EXISTS
                  ( SELECT *
                    FROM student_club AS scc 
                    WHERE scc.student_id = sc.id
                      AND scc.club_id = c.club_id  
                  )
          )
    

    Another approach:

    SELECT s.stud_id
    FROM   student s
    
    EXCEPT
    
    SELECT stud_id
    FROM 
      ( SELECT s.stud_id, c.club_id
        FROM student s 
          CROSS JOIN (VALUES (30),(50)) c (club_id)
      EXCEPT
        SELECT stud_id, club_id
        FROM student_club
        WHERE club_id IN (30, 50)   -- optional. Not needed but may affect performance
      ) x ;   
    

提交回复
热议问题