2

Я начинаю работать с uniqueidentifiers, и я сталкиваюсь с неожиданной проблемой.Лучший способ получить новый уникальный идентификатор из инструкции вставки SQL, все еще определяя успех или неудачу вставки?

Прежде всего, где я обычно использую SCOPE_IDENTITY(), это уже невозможно с уникальным идентификатором, хотя в концепции по-прежнему подразумевается автоматическое генерируемое значение id в результате значения по умолчанию (newid() или newsequentialid()).

Я решил использовать предложение OUTPUT в инструкции INSERT для вывода UUID в переменную таблицы. Теперь, когда я думаю об этом, предложение OUTPUT делает SCOPE_IDENTITY устаревшим, учитывая, что это намного более ясный и более мощный способ достичь того же и большего (например, получить четкий и прямой доступ к нескольким автоматически сгенерированным столбцам для всех вставленных строк).

С использованием OUTPUT, однако, мне теперь интересно, как это влияет на тест @@ rowcount, который обычно следует за вставкой. Будет ли @ @ rowcount отражать количество строк, вставленных в основную инструкцию, или количество строк, вставленных в переменную таблицы, в выходное предложение?

Вы можете подумать, что это не повлияет (т. Е. Счет должен быть одним и тем же), но это имеет значение, потому что documentation говорит, что предложение OUTPUT будет возвращать значения и заполнять таблицу, даже если инструкция insert не работает.

UPDATE, INSERT или DELETE оператор, который имеет пункт OUTPUT будет возврата строки к клиенту, даже если оператор сталкивается с ошибками и откатывается. Результат не должен использоваться, если какая-либо ошибка возникает, когда запускает инструкцию.

В нем упоминается, что @@ rowcount, в частности, всегда будет отражать внешний оператор только при использовании OUTPUT, но он упоминает, что это контекст вложенного запроса. Поскольку предложение OUTPUT в моем случае является частью самого внешнего утверждения, неясно, будет ли @@ rowcount сообщать количество строк, вставленных в выходную таблицу, если инструкция insert не работает.

declare @new_uuid TABLE (ID uniqueidentifier); 
    insert into Users (ID, PersonID, Username, Password, Notes, Enabled) 
    output INSERTED.UUID into @new_uuid 
     values (@id, @personid, @username, @password, @notes, @enabled) 
    if (@@rowcount <> 1) goto fail; --does this reflect rows inserted into Users or @new_uuid? What if the insert fails, and rows are still output to @new_uuid? 
+0

'Будет ли @ @ rowcount отражать количество строк, вставленных в основной оператор, или количество строк, вставленных в переменную таблицы, в результате вывода?' Не быть рывком, но вы дали ему шанс? Кажется, что много написано для чего-то, что легко поддается проверке. – LittleBobbyTables

+1

Если вы часто задаете вопрос, чтобы решить проблему; и хотя я могу/попробовал/протестировал его и нашел ответ, я все равно отправляю вопрос ради сообщества, так что, если другие столкнутся с ситуацией, эта запись может помочь им. В то же время, даже если я проверю поведение экспериментально, это не отвечает на вопрос, есть ли лучший способ получить значения, или лучший способ проверить успех утверждения. Вопрос в том, как лучше всего подойти к этой простой задаче, а также продемонстрировать, как могут возникать сложные проблемы. – Triynko

+0

Действительные рассуждения, иметь upvote! – LittleBobbyTables

ответ

3

Я испытал это поведение экспериментально с помощью следующего кода TSQL:

create function NEWOBJECTID() returns int as begin return 1/0; end --function that would typically perform work to create a new object id, but intentionally throws an error instead 
go 

declare @uuidtable table (UUID uniqueidentifier); 

insert into Users (ID) 
output INSERTED.UUID into @uuidtable --UUID column has default constraint of (newid()) 
values (dbo.NEWOBJECTID()); --value to insert will throw an error 

print @@rowcount; --called immediately after statement to see how it was affected by the failure 
select * from @idtable; --see if anything was output into the table variable 

Результаты этого утверждения были что @@ ROWCOUNT вернулся к нулю, и есть нулевые строки, присутствующие в переменной @uuidtable, но, пожалуйста, продолжайте читать, потому что этот результат вводит в заблуждение.

ВПЕРВЫЕ, это привело меня к мысли, что, поскольку ни одна строка не была вставлена, никакого выхода не происходит. Это неверно, и это доказывает простая модификация.

insert into Users (ID) 
output INSERTED.UUID into @uuidtable --UUID column has default constraint of (newid()) 
values 
(1), --value to insert should succeed 
(2), --value to insert should succeed 
(dbo.NEWOBJECTID()); --value to insert will throw an error 

Когда я запустил его на этот раз @@ rowcount, все равно равен нулю; однако 2 строки с двумя новыми уникальными идентификаторами были OUTPUT в @uuidtable.

Это означает, что @@ rowcount отражает окончательное количество вставленных строк, которое равно нулю, потому что хотя первые два значения были вставлены успешно и OUTPUT в @uuidtable, оператор в целом был откат в результате Ошибка.

Поскольку две строки были вставлены в таблицу OUTPUT, но в результате ошибки оператора в конечном итоге были вставлены нулевые строки, а @@ rowcount сообщает об 0, что доказывает, что оно отражает количество строк, вставленных самим вставкой а не количество строк, вставленных в таблицу OUTPUT. Это также подтверждает то, что в документации говорит, что строки будут OUTPUT, даже если общий оператор терпит неудачу.