没有ORDER BY的SQL Server 2005 ROW_NUMBER()

时间:2011-01-26 22:10:34

标签: sql sql-server sql-server-2005 tsql auto-increment

我正在尝试使用

从一个表插入另一个表
DECLARE @IDOffset int;
SELECT @IDOffset = MAX(ISNULL(ID,0)) FROM TargetTable

INSERT INTO TargetTable(ID, FIELD)
SELECT [Increment] + @IDOffset ,FeildValue
FROM SourceTable
WHERE [somecondition]

TargetTable.ID不是标识列,这就是为什么我必须自己找到一种自动递增的方法。

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

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

2 个答案:

答案 0 :(得分:75)

您可以避免指定显式排序,如下所示:

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子句中允许的无常量”限制。出于某种原因,我更喜欢1而不是NULL

另外:我认为标识栏的优势非常优越,应该使用它。并发独占锁定整个表并不好。陈述。

答案 1 :(得分:3)

您可以使用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]