我有一个带有身份字段的表。从这个表中获取所有已删除记录的ID的最佳SQL查询是什么?
答案 0 :(得分:2)
您可以使用递归查询:
DECLARE @MaxId int
SELECT @MaxId = SELECT IDENT_CURRENT('MyTable');
WITH Ids AS (
SELECT 1 AS intId
UNION ALL
SELECT intId + 1
FROM Ids
WHERE intId < @MaxId
)
SELECT intId
FROM Ids AS i
WHERE NOT EXISTS (
SELECT NULL FROM MyTable AS m
WHERE m.intId = i.intId
)
OPTION (MAXRECURSION 0)
如果表非常大,这将不会非常有效。
答案 1 :(得分:2)
完全不同的方法是:
SELECT a.intId, b.intId
FROM MyTable a
CROSS JOIN MyTable b
WHERE a.intId + 1 < b.intId
AND NOT EXISTS (
SELECT NULL FROM MyTable c
WHERE c.intId > a.intId
AND c.intId < b.intId
)
这将提供已删除所有记录的ID对。
因此,如果ID是(1,2,3,6,7,12),它将返回(3,6)和(7,12)。
编辑:
如果表很大,这是非常低效的。以下方法要好得多:
SELECT g.intStartId, MIN(t.intId) AS intEndId
FROM (
SELECT intId AS intStartId
FROM MyTable AS a
WHERE NOT EXISTS (
SELECT NULL FROM MyTable AS b
WHERE b.intId = a.intId + 1
)
) AS g
CROSS JOIN MyTable AS t
WHERE t.intId > g.intStartId
GROUP BY g.intStartId
因此,我们首先找到标记间隙开始的ID,然后我们找到比标记间隙末尾更大的ID。
答案 2 :(得分:2)
使用数字表左连接并获取所有空数,这使用内置数字表,但最好有自己的
代码看起来像
的示例create table #bla(id int)
insert #bla values(1)
insert #bla values(2)
insert #bla values(4)
insert #bla values(5)
insert #bla values(9)
insert #bla values(12)
select number from master..spt_values s
left join #bla b on s.number = b.id
where s.type='P'
and s.number < (select MAX(id) from #bla)
and b.id is null
输出
0 3 6 7 8 10 11
请参阅此处:How to return all the skipped identity values from a table in SQL Server了解更多详情
答案 3 :(得分:1)
一个选项是创建一个临时表/可嵌入SQL语句,其中包含所有可能的ID(this article中列出了一些选项),最多包括表的最大(标识)。
然后,您可以使用您的表从此规范值列表中继续加入,并在右侧的空值上过滤。
答案 4 :(得分:1)
关注顺序ID列的查询是不够的。如果事务失败,ID
序列可能会在插入期间跳过数字,因此如果您ID = (1,3)
并不意味着ID=2
已被删除,则可能已跳过该OUTPUT DELETED.*
序列。
您必须使用某些东西来捕获已删除的记录,例如触发器或{{1}} - 或使用某些内容进行比较,如快照,备份和历史记录表。
答案 5 :(得分:0)
一种完全不同的方法,确实需要对您的示例进行重构,不是从表中删除,而是要有一个单独的已删除项ID的表(或者在表中有一个字段显示行的状态) 。因此,您可以选择这些数据。 (这将围绕@ Damir的观察,即你无法区分删除和插入错误。)