我可以基于SQL if语句联接表吗?

我可以基于SQL if语句联接表吗?,sql,mysql,Sql,Mysql,我有三个表格用于解决这个问题:歌曲、黑名单和白名单。songs表有一个名为“accessType”的列,该列存储以下四个值之一:public、private、blacklist和whitelist。我正在尝试获取用户可以访问的所有歌曲的列表。第一个条件是songs.accessType!=私有的棘手的部分来了:如果songs.accessType=blacklist,我需要检查用户的ID是否不在黑名单表中。类似地,如果songs.accessType=whitelist,我需要检查用户的ID是否

我有三个表格用于解决这个问题:歌曲、黑名单和白名单。songs表有一个名为“accessType”的列,该列存储以下四个值之一:public、private、blacklist和whitelist。我正在尝试获取用户可以访问的所有歌曲的列表。第一个条件是songs.accessType!=私有的棘手的部分来了:如果songs.accessType=blacklist,我需要检查用户的ID是否不在黑名单表中。类似地,如果songs.accessType=whitelist,我需要检查用户的ID是否在白名单表中。在我看来,在某些条件下,我需要加入黑名单和/或白名单,但我不知道这是否可行,甚至不知道正确的方法。非常感谢您的帮助,谢谢

下面是对我的表模式的解释:

歌曲:id,name,acessType,userID

黑名单:songID,userID

白名单:songID,userID

编辑
下面是外键的分类:
songs.id->blacklist.songID
songs.id->whitelist.songID
songs.userID->blacklist.userID
songs.userID->whitelist.userID

拉维什的答案是有效的,但我很想知道为什么人们说它效率不高

另外,userID前面的@符号的意义是什么?我将@userID替换为?我将参数绑定到查询


@Workshop Alex-完全不应包括私人歌曲。

您尝试使用两个条件(userID和accessType)连接两个表。

您尝试使用两个条件(userID和accessType)连接两个表.

ON
子句中使用字符串比较,并智能地加入黑名单和白名单

    SELECT `s`.*
      FROM `songs` `s`
INNER JOIN `whitelist` `w`
        ON `s`.`id` = `w`.`songID`
       AND `s`.`userID` = `w`.`userID`
       AND `s`.`accessType` = 'whitelist';
 LEFT JOIN `blacklist` `b`
        ON `s`.`id` = `b`.`songID`
       AND `s`.`userID` = `b`.`userID`
       AND `s`.`accessType` = 'blacklist'
     WHERE `b`.`songID` IS NULL
       AND `s`.`accessType` <> 'private'
       AND `s`.`userID` = $youruserid;
选择's'*
来自“歌曲”`
内部联接“白名单”`w`
在's`.'id`='w`.'songID上`
和's`.'userID`='w`.'userID``
和's`.'accessType`='whitelist';
左加入“黑名单”`b`
在's`.'id`='b`.'songID上`
和's`.'userID`='b`.'userID``
和's`.'accessType`='blacklist'
其中'b`.'songID'为空
和's`.'accessType`'private'
和's`.'userID`=$youruserid;
这将为给定的
用户ID
选择所有歌曲,这些歌曲是公共的,与
白名单
内部连接(因此您只能在白名单上获得歌曲)

然后,与
黑名单
的左连接只选择没有黑名单条目的行


顺便说一句,我不太清楚你的外键关系是什么,也许你可以详细说明一下?

ON
子句中使用字符串比较,并智能地加入你的黑名单和白名单

    SELECT `s`.*
      FROM `songs` `s`
INNER JOIN `whitelist` `w`
        ON `s`.`id` = `w`.`songID`
       AND `s`.`userID` = `w`.`userID`
       AND `s`.`accessType` = 'whitelist';
 LEFT JOIN `blacklist` `b`
        ON `s`.`id` = `b`.`songID`
       AND `s`.`userID` = `b`.`userID`
       AND `s`.`accessType` = 'blacklist'
     WHERE `b`.`songID` IS NULL
       AND `s`.`accessType` <> 'private'
       AND `s`.`userID` = $youruserid;
选择's'*
来自“歌曲”`
内部联接“白名单”`w`
在's`.'id`='w`.'songID上`
和's`.'userID`='w`.'userID``
和's`.'accessType`='whitelist';
左加入“黑名单”`b`
在's`.'id`='b`.'songID上`
和's`.'userID`='b`.'userID``
和's`.'accessType`='blacklist'
其中'b`.'songID'为空
和's`.'accessType`'private'
和's`.'userID`=$youruserid;
这将为给定的
用户ID
选择所有歌曲,这些歌曲是公共的,与
白名单
内部连接(因此您只能在白名单上获得歌曲)

然后,与
黑名单
的左连接只选择没有黑名单条目的行

另外,我不太确定您的外键关系是什么,也许您可以详细说明一下?

SELECT*
从歌曲
其中(s.AccessType='BlackList'和@UserId)
不在(从黑名单中选择UserId,其中SongId=s.Id))
或(s.AccessType='WhiteList'和@UserId)
在中(从白名单中选择UserId,其中SongId=s.Id))
选择*
从歌曲
其中(s.AccessType='BlackList'和@UserId)
不在(从黑名单中选择UserId,其中SongId=s.Id))
或(s.AccessType='WhiteList'和@UserId)
在中(从白名单中选择UserId,其中SongId=s.Id))
如果accesstype=private,它就不会漏掉,不需要额外的子句

我选择使用相关子查询,因为在本例中,它们比过滤的左连接更可读。也许MySQL在这方面的效率要低一点,但人们不应该基于查询优化器的微小临时限制来决定设计,除非性能差异是绝对关键的。也许MySQL的下一个版本会比左连接更快

如果accesstype=private,它就不会漏掉,不需要额外的子句


我选择使用相关子查询,因为在本例中,它们比过滤的左连接更可读。也许MySQL在这方面的效率要低一点,但人们不应该基于查询优化器的微小临时限制来决定设计,除非性能差异是绝对关键的。也许MySQL的下一个版本会比左连接更快。

关于这个问题有点困惑!一些答案假设您在某个地方选择了一个用户ID,并希望为此特定用户选择所有歌曲。其他人认为您只是想要一个所有用户的列表,其中(userID,songID)在白名单中,但不在黑名单中。因此,这个问题有两个可能的答案

因此,它可以理解为两个不同的问题:
问题1:给定一个特定用户,他可以访问哪些公开、白名单或非黑名单的非私人歌曲?
问题2:哪些非私人歌曲的用户被列入白名单、公开名单或非黑名单?

两个问题都得到了回答。问题2由我回答,另一个由我回答。在Q2中,使用EXISTS是最好的选择,因为子选择总是返回单个结果
SELECT * FROM SONGS s
WHERE
   accesstype='public'
   OR (accesstype='whitelist' 
      AND EXISTS (SELECT null FROM WHITELIST wl WHERE 
          wl.songid = s.id AND wl.userid=s.userid))
   OR (accesstype='blacklist' 
      AND NOT EXISTS (SELECT null FROM BLACKLIST bl WHERE 
          bl.songid = s.id AND bl.userid= s.userid))