Получить следующий номер при вставке, сбросить до 0 в новый год - PullRequest
2 голосов
/ 21 марта 2012

Я сохраняю документы в базе данных, каждый документ должен иметь идентификатор в формате YYYY-00000:

  • первые 4 символа - текущий год
  • вторые пятьсимволы цифры.Они начинаются с 1 каждый год, а затем увеличиваются.

Например, у меня могут быть эти документы в моей базе данных: 2011-00001, 2011-00002, 2011-00003, 2012-00001, 2012-00002,...

Я думаю, что-то вроде этого:

  • добавить два столбца в таблицу Документы (год и номер)
  • Год вычисляемый столбец, что-то вроде year(getdate())
  • Число - это вычисляемый столбец, который получает значение из функции GetNextNumberForCurrentYear
  • GetNextNumberForCurrentYear возвращает следующий номер для текущего года (например, select max(Number) + 1 from Documents where Year = year(getdate()) и некоторая проверка нуля)

Но я боюсь, что два пользователя могут захотеть сохранить документ одновременно и получить один и тот же номер.Это возможно?Есть идеи получше?

Это веб-приложение ASP.NET C #, .NET 4.0, MSSQL 2005, у меня есть контроль над всеми частями приложения.

PS: после вставки яхотел бы вернуть идентификатор нового документа пользователю, поэтому мне, вероятно, придется сделать что-то вроде: select Id from Documents where SomeId = scope_identity(), поэтому я предполагаю, что где-то должен быть столбец идентификаторов ...?

Edit (окончательное решение): я получаю следующий номер из хранимой процедуры, строю Id документа (в формате YYYY-00001) в .NET, сохраняю весь документ в базу данных (используя TransactionScope для всего процесса), а затем возвращаю Id вПользователь.

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

1 Ответ

2 голосов
/ 21 марта 2012

Вы можете создать таблицу NumberSeries, которая содержит столбец Year и столбец CurrentNo, а также функцию, которая возвращает из нее следующий номер, например:

DECLARE @myResult TABLE (nextNumber INT)

UPDATE NumberSeries
OUTPUT INSERTED.NextNo INTO @myResult
SET
    CurrentNo = ISNULL(CurrentNo, 0) + 1
WHERE
    Year = Year(GetDate())

DECLARE @result INT
@result = (SELECT TOP 1 nextNumber FROM @myResult)

RETURN @result

Это обновлениетаблица NumberSeries атомарно и вставляет новое значение в переменную таблицы @myResult.После этого он возвращает первое (и единственное) значение из табличной переменной @myResult.

Все остальное, например SCOPE_IDENTITY(), может вызвать ошибки при использовании триггеров или в других случаях - решение с использованиемOUTPUT предложение безопасно.

РЕДАКТИРОВАТЬ
Что касается возврата идентификатора вставленного документа: это в основном то же самое.

DECLARE @myDocId TABLE (yr int, no int)

INSERT INTO Documents
OUTPUT INSERTED.Year , INSERTED.YearID INTO @myDocID
...

SELECT TOP 1
    CAST(yr AS NVARCHAR) + 
    '_' + 
    RIGHT(REPLICATE('0', 5) + CAST(no AS NVARCHAR), 5) AS NewID
...