Sql server 2008 在SQL Server 2008中查找丢失的ID

Sql server 2008 在SQL Server 2008中查找丢失的ID,sql-server-2008,tsql,Sql Server 2008,Tsql,我有一个包含两列的表 ID | Name ---------------- 1 | John 2 | Sam 3 | Peter 6 | Mike 它错过了ID。在这种情况下,它们是4和5 如何查找并将它们与随机名称一起插入此表 更新:不允许使用游标和临时表。随机名称应为“name_uu”+某个随机数。可能是指定的值,如“Abby”。所以这并不重要。从选择表中的最大数字开始,选择top 1 id desc,或选择maxid,然后运行while循环,从1…max开始迭代 看 对于每次迭代

我有一个包含两列的表

ID | Name
----------------
1  | John
2  | Sam
3  | Peter
6  | Mike
它错过了ID。在这种情况下,它们是4和5

如何查找并将它们与随机名称一起插入此表


更新:不允许使用游标和临时表。随机名称应为“name_uu”+某个随机数。可能是指定的值,如“Abby”。所以这并不重要。

从选择表中的最大数字开始,选择top 1 id desc,或选择maxid,然后运行while循环,从1…max开始迭代


对于每次迭代,请查看行是否存在,如果不存在,请使用该ID插入到表中。

首先选择表中的最大数字,选择top 1 ID desc,或选择maxid,然后运行while循环,从1…max开始迭代


对于每个迭代,查看行是否存在,如果不存在,则使用该ID插入到表中。

使用递归CTE,您可以确定缺少的ID,如下所示

DECLARE @Table TABLE(
        ID INT,
        Name VARCHAR(10)
)

INSERT INTO @Table VALUES (1, 'John'),(2, 'Sam'),(3,'Peter'),(6, 'Mike')

DECLARE @StartID INT,
        @EndID INT

SELECT  @StartID = MIN(ID),
        @EndID = MAX(ID)
FROM    @Table

;WITH IDS AS (
        SELECT  @StartID IDEntry
        UNION ALL
        SELECT  IDEntry + 1
        FROM    IDS
        WHERE   IDEntry + 1 <= @EndID
)
SELECT  IDS.IDEntry [ID]
FROM    IDS LEFT JOIN
        @Table t    ON  IDS.IDEntry = t.ID
WHERE   t.ID IS NULL
OPTION (MAXRECURSION 0)
选项MAXRECURSION 0将允许代码避免SQL SERVER的递归限制

从和

MAXRECURSION number指定最大递归数 允许进行此查询。数字是介于0和之间的非负整数 32767指定0时,不应用任何限制。如果未指定此选项,则服务器的默认限制为100

达到MAXRECURSION限制的指定数或默认数时 在查询执行期间,查询结束并返回错误

由于此错误,语句的所有效果都将回滚。 如果该语句是SELECT语句,则会导致部分结果或无结果 可能会被退回。返回的任何部分结果可能不包括所有行 在超过指定的最大递归级别的递归级别上


生成随机名称将受到此类名称的要求以及此类名称的列类型的很大影响。这个随机名称究竟意味着什么?

使用递归CTE,您可以如下确定缺少的ID

DECLARE @Table TABLE(
        ID INT,
        Name VARCHAR(10)
)

INSERT INTO @Table VALUES (1, 'John'),(2, 'Sam'),(3,'Peter'),(6, 'Mike')

DECLARE @StartID INT,
        @EndID INT

SELECT  @StartID = MIN(ID),
        @EndID = MAX(ID)
FROM    @Table

;WITH IDS AS (
        SELECT  @StartID IDEntry
        UNION ALL
        SELECT  IDEntry + 1
        FROM    IDS
        WHERE   IDEntry + 1 <= @EndID
)
SELECT  IDS.IDEntry [ID]
FROM    IDS LEFT JOIN
        @Table t    ON  IDS.IDEntry = t.ID
WHERE   t.ID IS NULL
OPTION (MAXRECURSION 0)
选项MAXRECURSION 0将允许代码避免SQL SERVER的递归限制

从和

MAXRECURSION number指定最大递归数 允许进行此查询。数字是介于0和之间的非负整数 32767指定0时,不应用任何限制。如果未指定此选项,则服务器的默认限制为100

达到MAXRECURSION限制的指定数或默认数时 在查询执行期间,查询结束并返回错误

由于此错误,语句的所有效果都将回滚。 如果该语句是SELECT语句,则会导致部分结果或无结果 可能会被退回。返回的任何部分结果可能不包括所有行 在超过指定的最大递归级别的递归级别上


生成随机名称将受到此类名称的要求以及此类名称的列类型的很大影响。这个随机名称到底需要什么?

您可以使用递归公共表表达式CTE来实现这一点。下面是一个示例:

DECLARE @MaxId INT
SELECT @MaxId = MAX(ID) from MyTable
;WITH Numbers(Number) AS 
(
    SELECT 1
    UNION ALL
    SELECT Number + 1 FROM Numbers WHERE Number < @MaxId 
)
SELECT n.Number, 'Random Name'
FROM Numbers n
LEFT OUTER JOIN MyTable t ON n.Number=t.ID
WHERE t.ID IS NULL

这里有几篇关于CTE的文章,对您很有帮助,您可以使用递归公共表表达式CTE来实现这一点。下面是一个示例:

DECLARE @MaxId INT
SELECT @MaxId = MAX(ID) from MyTable
;WITH Numbers(Number) AS 
(
    SELECT 1
    UNION ALL
    SELECT Number + 1 FROM Numbers WHERE Number < @MaxId 
)
SELECT n.Number, 'Random Name'
FROM Numbers n
LEFT OUTER JOIN MyTable t ON n.Number=t.ID
WHERE t.ID IS NULL

这里有几篇关于CTE的文章对我很有帮助,我认为递归CTE是一个更好的解决方案,因为它会更快,但下面是对我有用的:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestTable]') AND type in (N'U'))
DROP TABLE [dbo].[TestTable]
GO

CREATE TABLE [dbo].[TestTable](
    [Id] [int] NOT NULL,
    [Name] [varchar](50) NOT NULL,
 CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
))

GO

INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (1, 'John')
INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (2, 'Sam')
INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (3, 'Peter')
INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (6, 'Mike')
GO

declare @mod int
select @mod = MAX(number)+1 from master..spt_values where [type] = 'P'

INSERT INTO [dbo].[TestTable]
SELECT y.Id,'Name_' + cast(newid() as varchar(45)) Name from
(
    SELECT TOP (select MAX(Id) from [dbo].[TestTable]) x.Id from
    (
        SELECT 
        t1.number*@mod + t2.number Id
        FROM master..spt_values t1
        CROSS JOIN master..spt_values t2
        WHERE t1.[type] = 'P' and t2.[type] = 'P'
    ) x
    WHERE x.Id > 0 
    ORDER BY x.Id
) y
LEFT JOIN [dbo].[TestTable] on [TestTable].Id = y.Id
where [TestTable].Id IS NULL
GO

select * from [dbo].[TestTable]
order by Id
GO

我认为递归CTE是一个更好的解决方案,因为它会更快,但以下是对我有效的方法:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestTable]') AND type in (N'U'))
DROP TABLE [dbo].[TestTable]
GO

CREATE TABLE [dbo].[TestTable](
    [Id] [int] NOT NULL,
    [Name] [varchar](50) NOT NULL,
 CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
))

GO

INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (1, 'John')
INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (2, 'Sam')
INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (3, 'Peter')
INSERT INTO [dbo].[TestTable]([Id],[Name]) VALUES (6, 'Mike')
GO

declare @mod int
select @mod = MAX(number)+1 from master..spt_values where [type] = 'P'

INSERT INTO [dbo].[TestTable]
SELECT y.Id,'Name_' + cast(newid() as varchar(45)) Name from
(
    SELECT TOP (select MAX(Id) from [dbo].[TestTable]) x.Id from
    (
        SELECT 
        t1.number*@mod + t2.number Id
        FROM master..spt_values t1
        CROSS JOIN master..spt_values t2
        WHERE t1.[type] = 'P' and t2.[type] = 'P'
    ) x
    WHERE x.Id > 0 
    ORDER BY x.Id
) y
LEFT JOIN [dbo].[TestTable] on [TestTable].Id = y.Id
where [TestTable].Id IS NULL
GO

select * from [dbo].[TestTable]
order by Id
GO

其实很简单:

创建一个名为All_numbers的表,该表应包含您要查找的范围内的所有自然数

列表是包含您的数据的表

select a.num as missing_number ,
       'Random_Name' + convert(varchar, a.num) 
from #All_numbers a left outer join #list l on a.num = l.Id
where l.id is null

其实很简单:

创建一个名为All_numbers的表,该表应包含您要查找的范围内的所有自然数

列表是包含您的数据的表

select a.num as missing_number ,
       'Random_Name' + convert(varchar, a.num) 
from #All_numbers a left outer join #list l on a.num = l.Id
where l.id is null

当你说随机名称时,你真的是想用其他名称填充未使用的数据槽吗?或者,您真的希望生成随机的其他名称吗?我认为您需要详细说明随机名称,以便人们在这方面为您提供帮助。为什么要这样做呢?实际上,在跳过的ID中插入新值从来都不是一个好主意,尤其是如果它们是大多数数据库中可能存在的身份。闻起来像家庭作业。为什么不允许使用游标和临时表?当你说随机名称时,你真的是想用其他名称填充未使用的数据槽吗?或者,您真的希望生成随机的其他名称吗?我认为您需要详细说明随机名称,以便人们在这方面为您提供帮助。您为什么要这样做,在跳过的ID中插入新值实际上从来都不是一个好主意,尤其是如果它们是可能的身份
在大多数数据库中。闻起来像家庭作业。为什么不允许使用光标和临时表?整洁。让我想删除我的答案。你的回答没有完成他问题的插入部分,但这只是对最后几行的一个小改动。让我想删除我的答案。你的回答没有完成他问题的插入部分,但这只是对最后几行的一个小改动。