【问题标题】:SQL : How to state that no element of a set can be present in another set?SQL:如何声明一个集合中的任何元素都不能出现在另一个集合中?
【发布时间】:2016-11-18 09:31:56
【问题描述】:

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

我在这个问题上纠结了一个多小时: "选择播放列表中未使用任何曲目的所有专辑"。

我想做这样的事情:

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)

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

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

【问题讨论】:

  • 您使用的是哪个 DBMS?

标签: sql subquery correlated-subquery


【解决方案1】:

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 
        )
        ;

【讨论】:

    【解决方案2】:

    使用left join 松散地连接表。然后按专辑分组,只取playlistitem 表中曲目为零的那些

    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
    

    【讨论】:

    • 谢谢,但是该练习特别要求使用相关子查询(将编辑问题)-我该如何以这种方式解决它?
    【解决方案3】:

    使用相关子查询但不使用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);
    

    【讨论】:

      【解决方案4】:

      首先创建一个子查询,该子查询有一个内部连接,将所有在 track 和 playlistitem 中连接的结果连接在一起。然后检查albuid 是否不在该列表中。我使用 distinct 仅获取子查询中的唯一值。

      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(),如另一个答案中所述。
      • distinct 不是一个函数 - 在括号之间放一列是完全没用的
      猜你喜欢
      • 2021-12-08
      • 2011-05-23
      • 1970-01-01
      • 2012-03-31
      • 2013-05-28
      • 2021-03-07
      • 1970-01-01
      • 2021-04-05
      • 2019-12-20
      相关资源
      最近更新 更多