在 IN 表达式中查找不存在记录的 id

Posted

技术标签:

【中文标题】在 IN 表达式中查找不存在记录的 id【英文标题】:Find id's where records do not exist for IN expression 【发布时间】:2016-06-08 11:08:37 【问题描述】:

任何人都可以帮助我解决一个我不时遇到但往往会长期解决的常见问题吗?我试图找到一种优雅的方法来识别给定大量值的表中不存在的 Id。

我收到了一个 Excel 表,其中包含 4000 多个字符串 id 的列表,我需要确定哪些在 SQL Server 表中不存在。

我的第一个操作是使用 Notepad++ 并将列表转换为类似于 'XX1'、'XX2'、'XX3' 等的 CSV 列表,然后运行 ​​SELECT * FROM [TABLE] WHERE [ID] IN ('XX1 ','XX2','XX3',...)。这显示的记录比 Excel 中显示的少 2 条,所以现在我需要筛选它们以确定哪两条不在数据库中。

感谢您的帮助。

保罗。

【问题讨论】:

通常情况下,您将拥有要签入一张表的 ID。然后你可以对带有记录的实际表进行 LEFT JOIN 并查看缺少什么 谢谢@juergend - 这是我在表格中没有 ID 的情况 - 这次你在 Excel 中呈现给我(有时通过电子邮件或其他方式,但基本上在db结构,否则会更简单) 感谢@LukStorms 是否有任何技巧可以将数据简单地放入临时表中而无需编写太多脚本?一旦它在那里,我对 TSQL 很满意,可以做我需要的事情,但我想知道是否有一种简单的方法可以将列表轻松放入数据库,然后使用。 @Paul 我添加了一个额外的答案,尽管 Lasse 的答案非常好。 【参考方案1】:

您可以连接使用表值构造函数生成的内联表,前提是它不会溢出那么多 id,在这种情况下,您需要将它们转储到表中。

一个VALUES表达式的行数限制为1000,根据the documentation:

直接在VALUES列表中插入行可以构造的最大行数为1000

要加入内联表,请使用以下语法:

INNER JOIN (VALUES (1), (2), ...) AS inline (id)

这是一个示例,使用此表(您的实际表):

CREATE TABLE databasetable (ID INT NOT NULL)
INSERT INTO databasetable VALUES (1), (2), (3), (5), (6), (8), (9), (10)

您可以像这样查询缺失值:

SELECT
    excel.id
FROM
    databasetable AS A
    RIGHT JOIN (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) AS excel (id)
        ON A.id = excel.id
WHERE
    A.id IS NULL

因此,您必须从 Excel 电子表格中生成 VALUES (1), (2), (3), ...)

要使用临时表,如果您有超过 1000 行:

DECLARE @EXCEL TABLE (ID INT)
INSERT INTO @EXCEL VALUES (1), (2), (3), ..... -- first 1000
INSERT INTO @EXCEL VALUES (1), (2), (3), ..... -- next 1000
INSERT INTO ...                                -- and so on

SELECT
    @excel.id
FROM
    databasetable AS A
    RIGHT JOIN @excel
        ON A.id = @excel.id
WHERE
    A.id IS NULL

【讨论】:

非常感谢!我之前使用过表值构造函数,但在这种情况下没有使用,并且对输入列表格式进行了一些操作,这对于刚刚超过 4000 个值非常有效,现在我找到了我丢失的 ID!非常感谢! 请注意我对可能限制的评论。可能是你不能创建一个有 4000 行的内联表,你必须看看什么是有效的。 您可能想在我编辑后不接受我的回答,稍等。 将您的示例与内联的 VALUES 表一起使用时,我通过列出的 4012 个值实现了我所需要的。这是在 SQL 2008 R2 SP1 上【参考方案2】:

只需几个演示即可添加到可能性中

通过表变量。 这次使用 NOT IN 子句:

DECLARE @varTbl TABLE(ID varchar(8));

insert into @varTbl values ('XX1'),('XX2');

select id from @varTbl 
where id not in (select distinct id from [SomeTable]);

通过仅在会话期间存在的临时表。 这次是 LEFT JOIN。

CREATE TABLE #tempTbl (ID varchar(8));

insert into #tempTbl values ('XX1'),('XX2');

select tmp.id 
from #tempTbl tmp
left join [SomeTable] t on (tmp.id = t.id)
where t.id is null
group by tmp.id
order by tmp.id;

另一种完全不同的方法是通过文件进行比较。 您首先将参考数据的 ID 和目标表中的 ID 导出到已排序的文本文件中。然后过滤掉参考数据中存在但目标表中不存在的行的差异。 在 Windows 上,您可以通过 PowerShell 执行此操作。

$ref = Get-Content WhatShouldBe.txt
$dest = Get-Content WhatIsNow.txt

Compare-Object $ref $dest |Where-Object $_.SideIndicator -eq "<=" |Select -ExpandProperty InputObject > WhatCanBeAdded.txt

【讨论】:

嗨 Luk,这些示例将显示数据库中存在但 IN 表达式中不存在的记录,这与我正在寻找的相反,但感谢您的尝试。 呵呵,我确实误会了。修正了语句。反正原理是一样的。 @Paul 我想知道如何通过将简单的文本文件与已排序的 ID 进行比较,在 Windows 上轻松做到这一点。所以我添加了一个使用 PowerShell 的解决方案。 虽然附加选项对我来说增加了太多复杂性(因为我对 PowerShell 不太熟悉),但令人印象深刻的是,您已经完成了附加选项!我希望将来我会记住 Lasse 使用的表值构造函数,因为它是一个快速而简单的提示,当你醒来时要记住 SSMS。干杯【参考方案3】:

相信你可以在数据库中创建表

如果您在 excel 工作表或电子邮件中获取文件,则将内容移动到 excel 工作表(如果是电子邮件)或使用 导入数据向导 直接将 excel 工作表导入临时表 之后,您可以轻松地比较临时表和原始表中的数据,这比在表变量或#temp 表中加载 id 容易得多。 该视频展示了如何将 excel 数据导入 sql server https://www.youtube.com/watch?v=Z1vqhYlwcyA

还随机检查所有值是否已填充,或者是否还插入了任何 NULL 值。

使用 IN 子句添加的另一件事可以有数千个值 可以抛出错误。请在 SO 中查看此页面 "IN" clause limitation in Sql Server

【讨论】:

优点,尤其是“IN”子句限制链接。谢谢!

以上是关于在 IN 表达式中查找不存在记录的 id的主要内容,如果未能解决你的问题,请参考以下文章

从一个表中查找另一个表中不存在的记录

Oracle/SQL - 在另一个表中查找或为空或可能不存在或为空的记录

如何确定记录是不是是 NOT IN 的一部分而不是不存在?

HQL 左外连接用于查找一个表中存在而其他表中不存在的记录

mysql:如果不存在则插入记录,否则返回记录的ID

Oracle查询查找表中不存在的记录?