t-sql - 从 SQL 插入语句获取新的 uniqueidentifier 同时仍确定插入成功或失败的最佳方法?

标签 t-sql uniqueidentifier identity-column rowcount output-clause

我开始使用 uniqueidentifiers,但遇到了意外问题。

首先,在我通常使用 SCOPE_IDENTITY() 的地方,这对于 uniqueidentifier 来说不再是可能的,即使在概念上它仍然涉及一个自动生成的 id 值作为默认值(newid() 或newsequentialid()) 约束。

我决定在 INSERT 语句中使用 OUTPUT 子句将 UUID 输出到表变量。现在我想了一下,OUTPUT 子句使 SCOPE_IDENTITY 过时了,因为它是实现相同目标和更多功能的更清晰、更强大的方法(例如,为所有插入的行获得对多个自动生成的列的清晰和直接访问)。

但是,通过使用 OUTPUT,我现在想知道这如何影响通常在插入之后的 @@rowcount 测试。 @@rowcount 是否反射(reflect)主语句中插入的行数或输出子句插入到表变量中的行数?

您可能认为这不会有什么区别(即无论哪种方式计数都应该相同),但它确实有区别,因为 documentation表示即使插入语句失败,OUTPUT 子句也会返回值并填充表。

An UPDATE, INSERT, or DELETE statement that has an OUTPUT clause will return rows to the client even if the statement encounters errors and is rolled back. The result should not be used if any error occurs when you run the statement.

它确实提到,特别是 @@rowcount 仅在使用 OUTPUT 时才会始终反射(reflect)最外层的语句,但它提到这是嵌套查询的上下文。由于本例中的 OUTPUT 子句是最外层语句的一部分,因此不清楚如果插入语句失败,@@rowcount 是否会报告插入到输出表中的行数。

    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?

最佳答案

我通过以下 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 行被输出到 @uuidtable 中。

这表明@@rowcount反射(reflect)了最终插入的行数,该行数为零,因为尽管前两个值已成功插入并输出到@uuidtable,但由于以下原因,整个语句被回滚错误。

由于在 OUTPUT 表中插入了两行,但由于语句失败,最终插入了零行,并且 @@rowcount 报告为零,这证明它反射(reflect)了插入语句本身插入的行数,而不是比沿途插入到 OUTPUT 表中的行数。这也证实了文档所说的,即使整个语句失败,行也将被输出。

关于t-sql - 从 SQL 插入语句获取新的 uniqueidentifier 同时仍确定插入成功或失败的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19846498/

相关文章:

java - 计算许可证管理的唯一主机 ID?

php - 如何在排序列中添加 +1

SQL 标识列

sql - CASE 或 IF 然后 SELECT SQL

sql - 一周的开始(星期一) - 查询给出的日期不正确

sql-server - UniqueIdentifier 聚集索引上的 NewSequentialId

c# - 在 SQL Server 中将标识列重置为零?

sql-server - SQL - 从合并查询过滤器获取数据库名称

sql - 连接按列分组的值

MySQL:如何根据另一列创建唯一标识符