Добавить инкрементное целое число в строку таблицы базы данных при вставке, когда оно нарушает уникальное ограничение в представлении

У меня есть таблица базы данных с именем Form с двумя столбцами Id и UserName.

Я создал представление таблицы, в которой есть столбцы Id и UserName.

В этом представлении я создал УНИКАЛЬНЫЙ КЛАСТЕРНЫЙ ИНДЕКС для столбца UserName. Таким образом, всякий раз, когда пользователь пытается вставить повторяющееся значение для UserName, он будет вызывать уникальное исключение нарушения ограничения.

Есть ли способ выполнить приведенное ниже требование?
Мне нужно добавить увеличивающееся целое число, чтобы сделать имя пользователя уникальным.

Когда пользователь вводит имя пользователя, которое уже присутствует в таблице, оно должно добавлять к нему увеличенное целое число.

При вставке имени пользователя мы не всегда просто добавляем «1» в конец.
Мне нужно добавить увеличивающееся целое число, чтобы сделать имя пользователя уникальным.

  • Это соответствует поведению Windows при копировании файлов.

  • Если пользователь вставит «Том» 3 раза, он должен создать «Том 1», «Том 2» и «Том 3».

  • Если пользователь снова вставит «Том», он должен создать «Том 4».

  • Снова подумайте об этом: 

    • Если пользователь вручную вставляет «Том» и «Том 2» 

    • Затем пользователь вставляет «Том» — должно быть создано «Том 1».
       Затем пользователь снова вставляет «Том» — должно быть создано «Том 3», потому что «Том 2» уже существует.

  • Аналогичный каталог файлов Windows. Когда мы копируем/вставляем текстовый документ в какую-то папку, он снова и снова.

Мне нужна эта функциональность для получения уникального имени в CQRS с приложением EventSourcing, C#, где когда пользователь копирует какой-либо объект, например. FormName он должен просто добавить инкрементное целое число к FormName на основе имен форм, присутствующих в базе данных, и может возвращаться из базы данных. Таким образом, мы можем отобразить новое имя формы в пользовательском интерфейсе.


person Community    schedule 17.09.2015    source источник
comment
Это то, что можно сделать в блоке TRY...CATCH?   -  person Sam cd    schedule 17.09.2015
comment
Полная обработка в конце базы данных была бы предпочтительнее. Если это невозможно, мы можем подумать о блоке TRY...CATCH...   -  person    schedule 17.09.2015


Ответы (1)


Вы можете попробовать поймать конкретную ошибку в блоке TRY...CATCH в SQL, а затем отредактировать вставляемое значение:

declare @insert bit = 1
declare @uName varchar(20) = 'Tom'
declare @iteration int = 1
WHILE @insert = 1
BEGIN
    BEGIN TRY
    BEGIN TRANSACTION
      INSERT INTO [table](UserName) VALUES
      (@uName)
      SET @insert = 0
    COMMIT TRANSACTION
    END TRY

    BEGIN CATCH
      IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION
      SET @insert = 0
      IF ERROR_NUMBER() = 2601
      BEGIN
        IF ISNUMERIC(RIGHT(@uName,1)) = 1
        BEGIN
          SET @iteration = convert(int,RIGHT(@uName,1)) + 1
          SET @uName = LEFT(@uName,LEN(@uName) - 1)
        END
        SET @uName = @uName + convert(varchar,@iteration)
        SET @insert = 1
      END
    END CATCH
END

Чтобы получить точное значение ERROR_NUMBER(), которое вы ищете, вы можете выполнить тестовый прогон, преднамеренно вставив значение, которое нарушит уникальное ограничение, где находится ваш блок CATCH:

BEGIN CATCH
  SELECT ERROR_NUMBER()
END CATCH

EDIT Как указал @Roshan, правильным ERROR_NUMBER() для этого случая является Ошибка 2601

person Sam cd    schedule 17.09.2015
comment
В этом случае, если Tom1 уже присутствует, он будет добавлять 1 каждый раз, когда я создаю Tom, например Tom11, Tom111 и т. д. :( - person ; 17.09.2015
comment
@Roshan Отредактировано для таких случаев, или если вы начинаете с попытки вручную ввести добавленное имя пользователя - person Sam cd; 17.09.2015
comment
Я думаю, что это должно быть «ЕСЛИ ЧИСЛОВОЕ(ПРАВО(@uName,1)) = 1» вместо «ЕСЛИ ЧИСЛОВОЕ(ПРАВО(@uName,1)) = 0». - person ; 17.09.2015
comment
Также добавлен номер ошибки. :) . Он работает довольно хорошо. Большое спасибо @Sam - person ; 17.09.2015
comment
Хотите знать, как обрабатывать транзакции в этом случае? Как будто в случае исключения транзакция откатится. @Sam - person ; 20.09.2015
comment
@Roshan Поместите BEGIN TRANSACTION и COMMIT TRANSACTION в блок TRY и ROLLBACK TRANSACTION в блок CATCH, используя @@TRANCOUNT (см. правки) - person Sam cd; 21.09.2015