首页 > 解决方案 > 如何使用 SQL 检索不在另一个列表中的结果列表

问题描述

我有一个规范化的 SQL 数据库。相关架构如下所示:

User
---
ID,
EmailAddress,
CategoryID

EmailLog
--------
ID,
CategoryID,
UserID,
SentOn

我需要获取今天尚未针对特定类别发送电子邮件的用户列表。根据我的理解,我需要执行一个LEFT JOIN. 为了做到这一点,我尝试了以下方法:

DECLARE @Today AS DATETIME;
SET @Today = GETUTCDATE();

DECLARE @CategoryID AS INT;
SET @CategoryID = 101;

SELECT
  User.ID,
  User.EmailAddress,
FROM 
  (SELECT u.ID, u.EmailAddress, u.CategoryID FROM [dbo].[User] u WHERE u.CategoryID=@CategoryID) AS User
  LEFT JOIN
  (SELECT l.CategoryID l.SentOn FROM [dbo].[EmailLog] l WHERE l.CategoryID=@CategoryID AND DAY(l.SentOn)=DAY(@Today) AND MONTH(l.SentOn)=MONTH(@Today) AND YEAR(l.SentOn)=YEAR(@Today)) AS Log
  ON User.UserID = Log.UserID
WHERE
  Log.SentOn IS NULL

我在这个问题中使用子查询,因为我的实际查询更复杂。但是,我已经验证每个子查询都返回了我预期的结果。换句话说,第一个子查询返回一个User列表。第二个子查询返回今天EmailLog发送的电子邮件列表。

我被困在我检索今天尚未发送电子邮件的用户的部分。这就像我试图证明一个负面的。我错过了什么?

谢谢!

标签: sqlleft-join

解决方案


使用Log.SentOn IS NULL条件ON Clause代替Where Clause

SELECT
  User.ID,
  User.EmailAddress,
FROM 
  (SELECT u.ID, u.EmailAddress, u.CategoryID FROM [dbo].[User] u WHERE u.CategoryID=@CategoryID) AS User
  LEFT JOIN
  (SELECT l.CategoryID l.SentOn FROM [dbo].[EmailLog] l WHERE l.CategoryID=@CategoryID AND DAY(l.SentOn)=DAY(@Today) AND MONTH(l.SentOn)=MONTH(@Today) AND YEAR(l.SentOn)=YEAR(@Today)) AS Log
  ON User.UserID = Log.UserID and Log.SentOn IS NULL

推荐阅读