SQL小提琴:http://sqlfiddle.com/#!6/52c67/1
CREATE TABLE MailingList (EmployeeId INT, Email VARCHAR(50))
INSERT INTO MailingList VALUES (1, 'bob@co.com')
INSERT INTO MailingList VALUES (2, 'jill@co.com')
INSERT INTO MailingList VALUES (3, 'frank@co.com')
INSERT INTO MailingList VALUES (4, 'fred@co.com')
现在我从某处获得了EmployeeIds列表:1,2,3,4,5
我需要检查哪些employeeId不在Mailinglist表中。我希望得到结果" 5"在这种情况下,因为它不在邮件列表表中。
最简单的方法是什么?
是否有一种比生成临时表更简单的方法,插入值1,2,3,4,5然后执行选择...不在(选择...) - 或获取相同的加入。所以基本上没有创建临时表并插入数据,只是使用列表1,2,3,4,5。
答案 0 :(得分:1)
您可以使用EXCEPT命令。 例如:
SELECT *
FROM
(
SELECT 1 AS Id
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
) AS t
EXCEPT
SELECT Id FROM MailingList
答案 1 :(得分:1)
您似乎没有询问逻辑,只是关于如何“最佳”代表集合{1,2,3,4,5}
。
正如你所提到的,一个答案就是临时表。
另一个是带有一堆UNION ALL
语句的子查询或CTE。
另一种方法是在CTE或子查询中使用VALUES (1), (2), (3), (4), (5)
。
但这里有一个明显的观点。如果您的表格中包含EmployeeID
字段,那么 肯定 您有一个Employee
表格?既然如此,您应该能够从那里“衍生”您的5名员工?
(SELECT id FROM employee WHERE manager_id = 666)
or...
(SELECT id FROM employee WHERE staff_ref IN ('111', '222', '333', '444', '555'))
etc, etc...
<强> 编辑: 强>
至于实际逻辑,一旦你的集合代表你的5名员工,你可以使用LEFT JOIN
和IS NULL
进行“反加入”......
SELECT
Employee.*
FROM
Employee
LEFT JOIN
MailingList
ON MailingList.list_id = 789
AND MailingList.employee_id = Employee.id
WHERE
Employee.manager_id = 666
AND MailingList.employee_id IS NULL
=&GT;经理#666但不在邮件列表#789
的员工答案 2 :(得分:1)
每个人都在正确的轨道上,想到ANTI JOIN
。然而值得注意的是,所提出的答案并不总能产生完全相同的结果,并且每种解决方案都有不同的性能影响。 MatBailie提出的建议是如何进行ANTI JOIN,亚历山大建议的是如何进行ANTI SEMI JOIN
。
Alexander正在寻找正确的IMO,我们正在寻找的是ANTI SEMI JOIN;一个 LEFT ANTI SEMI JOIN,具体来说,您将“somewhere”中的employeeId列表作为 Left 表,将MailingList作为 Right 表。
ANTI JOIN返回 设置中 中 通过set我指的是一个表,视图,子查询等。通过“this”集我指的是LEFT表,而“that”集我指的是RIGHT表。 SEMI JOIN是仅返回LEFT表中一个匹配行的位置。换句话说,A SEMI连接返回 distinct 集。
现在我从某个地方获得了EmployeeIds列表
使用提供的样本数据。让我们说,通过“某处”,你在谈论一张桌子。 (我将两次数字包括在内,以证明ANTI JOIN和ANTI SEMI JOIN之间的区别)
CREATE TABLE dbo.somewhere (employeeId int);
INSERT dbo.somewhere VALUES (1),(2),(3),(4),(5),(5);
您可以使用NOT IN
或NOT EXISTS
-- ANTI JOIN USING NOT IN
SELECT somewhere.EmployeeId--, <other columns>
FROM dbo.somewhere
WHERE somewhere.EmployeeId NOT IN (SELECT EmployeeId FROM dbo.MailingList); -- EXLCLUDE IDs NOT IN MailingList
-- ANTI JOIN USING NOT EXISTS
SELECT somewhere.EmployeeId--, <other columns>
FROM dbo.somewhere
WHERE NOT EXISTS
(
SELECT EmployeeId
FROM dbo.MailingList ML
WHERE ML.EmployeeId = somewhere.employeeId
);
请注意,其中每个都返回数字5两次。如果您只需要使用EXCEPT来执行ANTI SEMI JOIN,那么:
SELECT somewhere.EmployeeId
FROM dbo.somewhere
EXCEPT -- SET OPERATOR (SET OPERATORS INCLUDE: UNION, UNION ALL, EXCEPT, INTERSECT)
SELECT EmployeeId
FROM dbo.MailingList; -- EXLCLUDE IDs NOT IN MailingList
除Set Operator
UNION
和INTERSECT
外,我是string_split
。集合运算符返回唯一的结果集。 (这是UNION ALL的一个例外)。如果您想使用NOT IN或NOT EXISTS获得唯一的结果集,则还需要包含DISTINCT或GROUP BY所有您想要唯一的列。
如果你在“某处”谈论逗号分隔的列表或XML或JSON文件/片段,那么你首先需要将该列表,XML,JSON或其他内容转换为LEFT表。使用SQL Server 2016的-- "somewhere" is a csv, list or array
DECLARE @somewhere varchar(1000) = '1,2,3,4,5';
-- ANTI JOIN WITH NOT IN
SELECT EmployeeId = [value]
FROM string_split(@somewhere, ',')
WHERE [value] NOT IN (SELECT EmployeeId FROM dbo.MailingList);
-- ANTI SEMI JOIN WITH NOT IN
SELECT DISTINCT EmployeeId = [value]
FROM string_split(@somewhere, ',')
WHERE [value] NOT IN (SELECT EmployeeId FROM dbo.MailingList);
-- ANTI SEMI JOIN WITH EXCEPT
SELECT EmployeeId = [value]
FROM string_split(@somewhere, ',')
EXCEPT
SELECT EmployeeId FROM dbo.MailingList;
GO
(或其他“拆分器”功能),您可以这样做:
-- "somewhere" is XML
DECLARE @somewhere XML =
'<employees>
<employee>1</employee>
<employee>2</employee>
<employee>3</employee>
<employee>4</employee>
<employee>5</employee>
</employees>'
-- ANTI SEMI JOIN using EXCEPT
SELECT employeeId = emp.id.value('.', 'int')
FROM (VALUES (@somewhere)) s(empid)
CROSS APPLY empid.nodes('/employees/employee') emp(id)
EXCEPT
SELECT employeeId
FROM dbo.MailingList;
..或者如果它是XML,一个选项看起来像这样:
RewriteEngine on
ErrorDocument 404 /404.php
RewriteRule ^signup$ signup.php [QSA,L]
RewriteRule ^signin$ signin.php [QSA,L]
RewriteRule ^home$ home.php [QSA,L]
RewriteRule ^messages$ messages.php [QSA,L]
RewriteRule ^signout$ signout.php [QSA,L]
RewriteRule ^settings$ settings.php [QSA,L]
RewriteRule ^settings/ChangePassword$ change_password.php [QSA,L]
RewriteRule ^settings/RemoveAccount$ remove_account.php [QSA,L]
RewriteRule ^message/([0-9]+)$ show_message.php?id=$1
最后。您想在邮件列表表中找到EmployeeId的索引。在我的示例中,您还需要dbo.somewhere上的索引。如果您正在进行SEMI连接,那么您希望这些索引是唯一的。