0

我有一个带有标识字段的表。从该表中获取所有已删除记录的 ID 的最佳 SQL 查询是什么?

4

6 回答 6

3

一种完全不同的方法是:

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 的最低 ID 来标记间隙的结束。

于 2010-01-18T11:31:25.323 回答
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)

虽然如果表非常大,这不会很有效。

于 2010-01-18T11:19:49.483 回答
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

请参阅此处:如何从 SQL Server 中的表中返回所有跳过的标识值以获取更多详细信息

于 2010-01-18T14:25:32.180 回答
1

一种选择是创建一个临时表/可嵌入的 SQL 语句,其中包含所有可能的 ID(本文概述了一些选项),最多包括表的最大(身份)。

然后,您可以将此规范值列表与您的表左连接,并在右侧过滤空值。

于 2010-01-18T11:31:31.593 回答
1

仅关注顺序 ID 列的查询是不够的。如果事务ID失败,序列可能会在插入期间跳过数字,所以如果你有ID = (1,3)它并不意味着它ID=2已被删除,它可能已被跳过。您必须使用某些东西来捕获已删除的记录,例如触发器,或者OUTPUT DELETED.*- 或者使用某些东西进行比较,例如快照、备份、历史表。

于 2010-01-18T11:32:17.243 回答
0

一种完全不同的方法(确实需要重构您的示例)是不要从表中删除,而是有一个单独的已删除项目 id 表(或在表中具有一个显示行状态的字段)。因此,您可以只选择这些数据。(这将围绕@Damir 的观察,即您无法区分删除和插入错误。)

于 2010-01-18T12:03:10.573 回答