我可以基于SQL if语句联接表吗?
我有三个表格用于解决这个问题:歌曲、黑名单和白名单。songs表有一个名为“accessType”的列,该列存储以下四个值之一:public、private、blacklist和whitelist。我正在尝试获取用户可以访问的所有歌曲的列表。第一个条件是songs.accessType!=私有的棘手的部分来了:如果songs.accessType=blacklist,我需要检查用户的ID是否不在黑名单表中。类似地,如果songs.accessType=whitelist,我需要检查用户的ID是否在白名单表中。在我看来,在某些条件下,我需要加入黑名单和/或白名单,但我不知道这是否可行,甚至不知道正确的方法。非常感谢您的帮助,谢谢 下面是对我的表模式的解释: 歌曲:id,name,acessType,userID 黑名单:songID,userID 白名单:songID,userID 编辑我可以基于SQL if语句联接表吗?,sql,mysql,Sql,Mysql,我有三个表格用于解决这个问题:歌曲、黑名单和白名单。songs表有一个名为“accessType”的列,该列存储以下四个值之一:public、private、blacklist和whitelist。我正在尝试获取用户可以访问的所有歌曲的列表。第一个条件是songs.accessType!=私有的棘手的部分来了:如果songs.accessType=blacklist,我需要检查用户的ID是否不在黑名单表中。类似地,如果songs.accessType=whitelist,我需要检查用户的ID是否
下面是外键的分类:
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))