SQL Server 2005 ROW_NUMBER() 没有 ORDER BY

Posted

技术标签:

【中文标题】SQL Server 2005 ROW_NUMBER() 没有 ORDER BY【英文标题】:SQL Server 2005 ROW_NUMBER() without ORDER BY 【发布时间】:2011-06-16 04:30:06 【问题描述】:

我正在尝试使用从一个表插入另一个表

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 的原始顺序(如果可能)。

谁能给点建议?

【问题讨论】:

源表上的聚集索引是什么?当您说“SourceTable 的原始顺序”时,我假设这就是您所说的?如果是堆,则没有特定的顺序。 【参考方案1】:

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

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

另外:我认为标识列要优越得多,应该改用。以独占方式锁定整个表对并发性不利。轻描淡写。

【讨论】:

@Emtucifor:第一个工作正常。至于第二个,事实是它确实返回了一个结果,无论如何都是一行。如果表为空,则返回 NULL,因此无需进行子选择,只需在 MAX() 上使用 ISNULL(),但不在其中。不知何故,我首先设法将其排除在外,实际上当时我可能没有多想。当我在 SO 上阅读某人的帖子时,纯属巧合让我了解到其他情况(现在不记得是哪一个了)。我在发布我的更正之前检查了它。为什么更好?嗯,我认为它只是看起来更简单,也更容易阅读。 这不一定是正确的,如果外部查询有一个ORDER BY 子句,或者在其他边缘情况下可以看到这里:***.com/q/18961789/521799 @LukasEder 我的回答是正确的,但它可能不如它本来的那么完整。如果有人正在寻找“保留原始顺序”并且不知道这是 SQL Server 中的一个无意义的概念,他们可能会尝试使用此代码来获取它——但会失败。我现在已经更新了我的答案来解决这个问题。 太好了,修复坦克 @Mohammad Anini 我已回滚您的编辑;我更喜欢这种语法,它在 SQL Server 中完全有效。请不要编辑代码,除非您 100% 绝对确定您需要这样做。【参考方案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]

【讨论】:

以上是关于SQL Server 2005 ROW_NUMBER() 没有 ORDER BY的主要内容,如果未能解决你的问题,请参考以下文章

已安装 SQL Server 2005,安装 SQL Server 2008 时提示需要删除 SQL Server 2005 Express 工具

SQL Server 2005 异常

急需SQL server 2005的介绍

SQL server2005 安装错误

已安装 SQL Server 2005,安装 SQL Server 2008 时提示需要删除 SQL Server 2005 Express 工具

如何转换SQL Server 2008数据库到SQL Server 2005