Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Server 2005 ROW_NUMBER() without ORDER BY

I am trying to insert from one table into another using

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 is not an identity column, which is why I have to find a way to auto-increment it myself.

I know I can use a cursor, or create a table variable with an identity column and a FieldValue field, populate that, then use it in my insert into...select, but that is not very efficient. I tried using the ROW_NUMBER function to increment, but I really don't have a legitimate ORDER BY field in the SourceTable that I can use, and would like to keep the original order of the SourceTable (if possible).

Can anyone suggest anything?

like image 929
Fragilerus Avatar asked Jan 26 '11 22:01

Fragilerus


People also ask

Can we use ROW_NUMBER without ORDER BY?

The row_number() window function can be used without order by in over to arbitrarily assign a unique value to each row.

Does row number need ORDER BY clause?

The function 'ROW_NUMBER' must have an OVER clause with ORDER BY. The ORDER BY clause determines the sequence in which the rows are assigned their unique ROW_NUMBER within a specified partition. It is required.” So apparently the window order clause is mandatory for the ROW_NUMBER function in SQL Server.

Can we use ROW_NUMBER without partition?

ROW_NUMBER() Function without Partition By clausePartition by clause is an optional part of Row_Number function and if you don't use it all the records of the result-set will be considered as a part of single record group or a single partition and then ranking functions are applied.

How do I find the default row number in SQL?

There is no inherent row number for a table row. ROW_NUMBER() gives you the number of the row only within a specific result set. So it is the expected result that you always get 1 when the result set contains only 1 record.


1 Answers

You can avoid specifying an explicit ordering as follows:

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}; 

However, please note that is merely a way to avoid specifying an ordering and does NOT guarantee that any original data ordering will be preserved. There are other factors that can cause the result to be ordered, such as an ORDER BY in the outer query. To fully understand this, one must realize that the concept "not ordered (in a particular way)" is not the same as "retaining original order" (which IS ordered in a particular way!). I believe that from a pure relational database perspective, the latter concept does not exist, by definition (though there may be database implementations that violate this, SQL Server is not one of them).

The reason for the lock hints is to prevent the case where some other process inserts using the value you plan to use, in between the parts of the query executing.

Note: Many people use (SELECT NULL) to get around the "no constants allowed in the ORDER BY clause of a windowing function" restriction. For some reason, I prefer 1 over NULL.

Also: I think an identity column is far superior and should be used instead. It's not good for concurrency to exclusively lock entire tables. Understatement.

like image 71
ErikE Avatar answered Sep 19 '22 23:09

ErikE