Question

I would like to have a SQL Server function dbo.GetNextNumber(), which would generate sequential numbers for each call. As far as I understand this is impossible with a native T-SQL function as SQL Server insists the functions has to be deterministic. But, if you could show me a native T-SQL function that does this would really make my day.

I thought perhaps this could be possible to write using a CLR function. As CLR functions are static, the sequence numbers need to be stored in the calling context of the set operation, as storing it as a static variable would result in several connections using the same sequence, resulting in not-so-sequential numbers. I do not know enough about embedded CLR to see if set operation's (select, update, delete, insert) calling context is reachable from the CLR side.

At the end of the day, the following query

select dbo.GetNextNumber() from sysobjects

must return the result

1
2
3
4
5

It is OK if another function call to reset the context is necessary like

exec dbo.ResetSequenceNumbers()

To prevent some misunderstandings and reduce the chances of wasting your time answering wrong question, please note that I am not looking for an ID generation function for a table and I am aware of some hacks (albeit using a proc not a function) that involves some temp tables with identity columns. The ROW_NUMBER() function is close but it also does not cut.

Thanks a lot for any responses

Kemal

P.S. It is amazing that SQL Server does have a built-in function for that. A function (provided that it cannot be used in joins and where clauses) is really easy to do and extremely useful, but for some reason it is not included.

Was it helpful?

Solution

As you have implemented the CLR sequence based on my article related to the calculation of Running Totals, you can achieve the same using the ROW_NUBER() function.

The ROW_NUMBER() function requires the ORDER BY in the OVER clause, however there is a nice workaround how to avoid sorting due to the ORDER BY. You cannot put an expression in the order by, but you can put SELECT aConstant there. So you can easily achieve number generating using below statement.

SELECT
    ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNumber,
    *
FROM aTable

OTHER TIPS

In the next version of SQL Server you can use a SEQUENCE to do this. In earlier versions it's easy enough to do by inserting to a separate "sequence table" (a table with only an IDENTITY column) and then retrieving the value with the SCOPE_IDENTITY() function. You won't be able to do that in a function but you can use a stored procedure.

Can you give more information about why ROW_NUMBER() doesn't cut it? In the specific example you give, ROW_NUMBER() (with appropriate clarification of OVER(ORDER BY)) certainly seems to match your criteria.

But there are certainly cases where ROW_NUMBER() might not be useful, and in those cases, there are usually other techniques.

Perhaps having this general function seems useful to you, but in most cases, I find a solution better tailored to the problem at hand is a better idea than a general purpose function which ends up causing more difficulties - like a leaky abstraction you are constantly working around. You specifically mention the need to have a reset function. No such thing is needed with ROW_NUMBER(), given that it has the OVER(PARTITION BY ORDER BY) which allow you to specify the grouping.

SQL Server Denali has a new sequence structure for developers It is easy to manage and maintain sequence numbers in SQL Server after Denali You can find details in Sequence Numbers in SQL Server

For other versions than Denali, you can use Sequence Tables. Here is a sample for Sequence Table in SQL Server For reading sequence number from sequence table, you should insert dummy records from this auto identity enabled sql table

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top