2012-03-21 5 views
2
года

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

  • первые 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()) и некоторые проверки IsNull)

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

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

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

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

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 
+0

Можете ли вы описать, какое приложение работает с базой данных? Это то, что вы тоже кодируете? –

+0

@DJQuimby: обновлен вопрос. – sventevit

+0

Просто обратите внимание: вам не нужно объявлять '@ result' и устанавливать' @ result', если вы выберете 'select' в качестве последнего оператора. Вы можете либо «выбрать @ result», либо удалить две строки, которые объявляют и устанавливают '@ result'. Это позволяет сохранить один запрос во временную таблицу. –

ответ

2

Вы можете создать таблицу 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 является безопасным.

EDIT
Что касается возвращения ID вставленного документа: это в основном то же самое.

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 
+0

Спасибо, отлично работает! Я использовал только ваш первый пример, см. Мое редактирование. – sventevit

+0

Что такое редактирование? –

+0

Теперь это в моем вопросе :) – sventevit

Смежные вопросы