没有ORDER BY的SQL Server 2005 ROW_NUMBER()

Fra*_*rus 29 sql t-sql sql-server sql-server-2005 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]
Run Code Online (Sandbox Code Playgroud)

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

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

谁能提出任何建议?

Eri*_*ikE 77

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

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};
Run Code Online (Sandbox Code Playgroud)

但请注意,这只是避免指定排序的一种方法,并不保证将保留任何原始数据排序.还有其他因素可能导致结果被排序,例如ORDER BY外部查询中的结果.要完全理解这一点,必须认识到"未订购(以特定方式)"的概念与"保留原始订单"(以特定方式订购!)不同.我认为,从一个纯粹的关系型数据库的角度来看,后者的概念不存在,根据定义(虽然有可能是数据库实现违反本时,SQL Server是不是其中之一).

锁定提示的原因是为了防止某些其他进程使用您计划使用的值插入执行查询的部分之间的情况.

注意:许多人(SELECT NULL)用来解决"窗口函数的ORDER BY子句中允许的无常量"限制.出于某种原因,我更喜欢1NULL.

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