使用左连接并检查该行是否存在以及另一个检查where子句

loy*_*low 13 sql sql-server

我有以下表格:

Users
Banned

SELECT u.*
FROM Users
WHERE u.isActive = 1
    AND
      u.status <> 'disabled'
Run Code Online (Sandbox Code Playgroud)

我不想包含用户也可能在禁止表中的任何行.

最好的方法是什么?

我可以这样做在子句中放置一个子查询,所以它做了类似的事情:

u.status <> 'disabled' and not exist (SELECT 1 FORM Banned where userId = @userId)
Run Code Online (Sandbox Code Playgroud)

我认为最好的方法是做LEFT JOIN,我怎么能这样做?

Gar*_*thD 23

根据这个答案,在SQL-Server中使用NOT EXISTS效率更高LEFT JOIN/IS NULL

SELECT  *
FROM    Users u
WHERE   u.IsActive = 1
AND     u.Status <> 'disabled'
AND     NOT EXISTS (SELECT 1 FROM Banned b WHERE b.UserID = u.UserID)
Run Code Online (Sandbox Code Playgroud)

编辑

为了完整起见,我就是这样做的LEFT JOIN:

SELECT  *
FROM    Users u
        LEFT JOIN Banned b
            ON b.UserID = u.UserID
WHERE   u.IsActive = 1
AND     u.Status <> 'disabled'
AND     b.UserID IS NULL        -- EXCLUDE ROWS WITH A MATCH IN `BANNED`
Run Code Online (Sandbox Code Playgroud)

  • @Mark Amery,这个答案链接指向一篇关于"NOT IN vs. NOT EXISTS vs. LEFT JOIN/IS NULL:SQL Server"的优秀文章,其中详细介绍了比此处答案更多的细节.这个答案清楚地总结了那篇长篇文章:`NOT EXISTS比LEFT JOIN/IS NULL更有效 (2认同)
  • +1 @GarethD 当需要在结果集中返回右表中的数据时,我倾向于仅使用左连接。如果不需要从右表返回数据,请利用反半连接运算符并仅检查是否不存在。 (2认同)

Bor*_*ort 8

你只需检查你从LEFT JOINBanned 获得的价值是NULL:

SELECT U.*
FROM Users U
    LEFT JOIN Banned B ON B.userId = U.userId
WHERE U.isActive = 1
    AND U.status <> 'disabled'
    AND B.userId IS NULL -- no match in the Banned table.
Run Code Online (Sandbox Code Playgroud)


Red*_*ter 5

select u.*
from Users u
left outer join Banned b on u.userId = b.userId
where u.isActive = 1
    and u.status <> 'disabled'
    and b.UserID is null
Run Code Online (Sandbox Code Playgroud)