2011-01-26 61 views
27

我试图从一个表插入到另一个是没有标识列,这就是为什么我要找到一种方法来自动 - 增加它自己。SQL Server 2005的ROW_NUMBER()没有ORDER BY

我知道我可以使用游标,或创建一个带有标识列和FieldValue字段的表变量,填充它,然后在我的insert into...select中使用它,但这不是非常有效。我尝试使用ROW_NUMBER函数来递增,但是我真的没有可以使用的SourceTable中的合法ORDER BY字段,并且希望保持SourceTable的原始顺序(如果可能)。

任何人都可以提出任何建议吗?

+2

什么是源表的聚集索引?我假设你说的“SourceTable的原始顺序”就是你说的吗?如果它是一堆,那么没有特定的顺序。 – 2011-01-26 22:38:50

回答

70

可避免指定明确排序如下:

INSERT dbo.TargetTable (ID, FIELD) 
SELECT 
    Row_Number() OVER (ORDER BY (SELECT 1)) 
     + Coalesce(
     (SELECT Max(ID) FROM dbo.TargetTable WITH (TABLOCKX, HOLDLOCK)), 
     0 
    ), 
    FieldValue 
FROM dbo.SourceTable 
WHERE {somecondition}; 

但是,请注意,仅仅是为了避免指定排序和不保证任何原始数据顺序将被保留的方式。还有其他因素可能导致结果被排序,例如外部查询中的ORDER BY。为了充分理解这一点,人们必须认识到,“不按照(以特定方式)排序”与“保留原始顺序”(以特定方式排列)不同。我认为从纯粹的关系数据库的角度来看,后一个概念不存在,的定义(虽然可能有数据库实现违反了这个,SQL Server不是其中之一)。

锁提示的原因是为了防止在查询执行的各个部分之间使用您计划使用的值插入其他一些进程。

注意:许多人使用(SELECT NULL)来解决“窗口函数的ORDER BY子句中允许的不允许的常量”限制。由于某种原因,我比NULL更喜欢1

另外:我认为身份专栏是非常优越的,应该用来代替。并发性并不擅长锁定整个表。轻描淡写。

+0

@Emtucifor:第一个工作正常。至于第二种情况,事实上它无论如何都会返回一行结果。如果表为空,则返回NULL,因此不需要进行子选择,只需在MAX()中使用ISNULL(),但不在其中。我不知何故设法首先解雇它,实际上我可能没有给它太多的想法。仅仅是巧合让我学习,否则当我在这里阅读某人的帖子时(现在不记得是哪一个)。在发布我的更正之前,我检查了它。为什么它更好?那么,我认为这只是看起来更简单,更容易阅读。 – 2011-01-27 21:00:18

+0

这不一定是正确的,如果外部查询有'ORDER BY`子句,或者在其他边缘情况下可以在这里看到:http://stackoverflow.com/q/18961789/521799 – 2013-09-23 14:25:16

2

您可以通过使用order by (select null)这样忽略排序:

declare @IDOffset int; 
select @IDOffset = max(isnull(ID, 0)) from TargetTable 

insert into TargetTable(ID, FIELD) 
select row_number() over (order by (select null)) + @IDOffset, FeildValue 
    from SourceTable 
where [somecondition]