SQL : 如何声明一个集合中的元素不能出现在另一个集合中?

SQL : How to state that no element of a set can be present in another set?

假设我有这个数据库方案:

这个问题我纠结了一个多小时: "Select all albums of which no track has been used in a playlist".

我想做这样的事情:

SELECT parentalbum.albumid FROM album AS parentalbum 
  INNER JOIN track 
    ON track.albumid = parentalbum.albumid 
  INNER JOIN playlistitem
    ON track.trackid = playlistitem.trackid            // Join the 3 tables
  WHERE NOT ((SELECT track.trackid FROM album 
                INNER JOIN track
                  ON album.albumid = track.albumid
                WHERE track.albumid = parentalbum.albumid ) // Select songs from one album
            IN playlistitem.trackid   )                   // Check if at least one element of the album is in a playlist? (faulty)

我的查询可能完全错误,所以我将不胜感激。

编辑:我忘了说,我被要求使用相关子查询来解决这个问题。谢谢!

使用 left join 松散地连接 table。然后按专辑分组,只取 playlistitem table

中的零曲目
select a.id, a.title
from album a
left join track t on t.albumid = a.albumid
left join playlistitem pi on pi.trackid = t.trackid
group by a.id, a.title
having sum(case when pi.trackid is not null then 1 else 0 end) = 0

首先创建一个子查询,它有一个内部联接,用于将曲目和播放列表项中连接的所有结果联接在一起。然后检查 albumid 是否不在该列表中。我使用 distinct 只获取子查询中 albumid 的唯一值。

SELECT a.albumid
FROM album a
WHERE a.albumid NOT IN 
(  SELECT DISTINCT t.albumid
   FROM track t
   INNER JOIN playlistitem p
   ON p.trackid = t.trackid
)

NOT EXISTS()是答案:

SELECT *        -- Select all albums
FROM album a
WHERE NOT EXISTS (      -- of which no track
    SELECT * FROM track t
    WHERE t.albumid = a.albumid
    AND EXISTS (
        SELECT * FROM playlistitem pi   -- has been used in a playlist
        WHERE pi.trackid = t.trackid    
        )
    )
        ;

更简单:

SELECT *        -- Select all albums
FROM album a    
WHERE NOT EXISTS (      -- of which no track
        SELECT * 
        FROM track t    -- has been used in a playlist
        JOIN playlistitem pi ON t.trackid = pi.trackid
        WHERE t.albumid = a.albumid 
        )
        ;

使用相关子查询但不使用 NOT EXISTS 的替代版本,只是因为...

Select a.*
  From Album As a
  Where 0 = (
    Select Count(*)
      From PlaylistItem As pi
      Join Track As t on pi.TrackID = t.TrackID
      Where t.AlbumID = a.AlbumID);