我有一个包含两列的表
ID | Name
----------------
1 | John
2 | Sam
3 | Peter
6 | Mike
它错过了 ID。在这种情况下,这些是4
和5
。
如何找到它们并将它们与随机名称一起插入到此表中?
更新:不允许使用游标和临时表。随机名称应该是 'Name_'+ 一些随机数。也许它是像'Abby'这样的指定值。所以没关系。
我有一个包含两列的表
ID | Name
----------------
1 | John
2 | Sam
3 | Peter
6 | Mike
它错过了 ID。在这种情况下,这些是4
和5
。
如何找到它们并将它们与随机名称一起插入到此表中?
更新:不允许使用游标和临时表。随机名称应该是 'Name_'+ 一些随机数。也许它是像'Abby'这样的指定值。所以没关系。
使用递归 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 的递归限制
来自查询提示和WITH common_table_expression (Transact-SQL)
MAXRECURSION number 指定此查询允许的最大递归数。number 是介于 0 和 32767 之间的非负整数。指定 0 时,不应用限制。如果未指定此选项,则服务器的默认限制为 100。
在查询执行期间达到指定的或默认的 MAXRECURSION 限制数时,查询将结束并返回错误。
由于此错误,该语句的所有效果都将回滚。如果语句是 SELECT 语句,则可能返回部分结果或不返回结果。返回的任何部分结果可能不包括超出指定最大递归级别的递归级别的所有行。
生成RANDOM名称将在很大程度上受到此类名称的要求以及此类名称的列类型的影响。这个随机名称究竟意味着什么?
您可以使用递归公用表表达式 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
首先选择表中的最大数字(选择前 1 个 id desc),或选择 max(id),然后运行 while 循环以从 1...max 迭代。
请参阅这篇关于循环的文章。
对于每次迭代,查看该行是否存在,如果不存在,则使用该 ID 插入表中。
我认为递归 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 的表,该表应包含您要查找的范围内的所有自然数。
#list 是包含您的数据的表
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