I am saving documents to database, each document has to have an id with the format YYYY-00000:
- the first 4 characters are the current year
- the second five characters are numbers. They start with 1 each year and then increment.
For example I could have these documents in my database: 2011-00001, 2011-00002, 2011-00003, 2012-00001, 2012-00002, …
I am thinking something like this:
- add two columns to table Documents (Year and Number)
- Year is computed column, something like
year(getdate()) - Number is computed column, which gets value from a function
GetNextNumberForCurrentYear - GetNextNumberForCurrentYear returns next number for the current year (for example
select max(Number) + 1 from Documents where Year = year(getdate()), and some isnull checking)
But i fear, that two users could want to save the document at the same time and that they would receive the same Number. Is this possible? Any better ideas?
It is a ASP.NET C# web application, .NET 4.0, MSSQL 2005, I have the control over all the parts of the application.
PS: after insert I would like to return the Id of the new document to the user, so I would probably have to do something like: select Id from Documents where SomeId = scope_identity(), so I guess there should be an identity column somewhere…?
Edit (final solution): I get the next number from stored procedure, build the Id of the document (in format YYYY-00001) in .NET, save the whole document to the database (using TransactionScope for whole process) and then return the Id to the user.
create table DocumentNumbers ([Year] int not null, Number int not null default 1)
insert into DocumentNumbers ([Year], Number)
select 2012, 1 -- and more...
create procedure GetNextDocumentNumber
@year int
as
begin
declare @myResult table (nextNumber int)
update DocumentNumbers
set Number = isnull(Number, 0) + 1
output inserted.Number into @myResult
where [Year] = @year
select top 1 nextNumber from @myResult
end
You could create a table
NumberSeries, which contains a columnYearand a columnCurrentNoand a function that returns the next number from it like the following:This updates the
NumberSeriestable atomically and inserts the new value into the@myResulttable variable. After that, it returns the first (and only) value from the@myResulttable variable.Everything else, like
SCOPE_IDENTITY()and such may cause errors when using triggers or in other cases – the solution using theOUTPUTclause is safe.EDIT
As for returning the ID of the inserted document: this is basically the same thing.