2011-01-26 98 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]