【问题标题】:Best way to obtain new uniqueidentifier from an SQL insert statement while still determining success or failure of insertion?从 SQL 插入语句中获取新唯一标识符的最佳方法,同时仍确定插入成功或失败?
【发布时间】:2013-11-07 20:54:25
【问题描述】:

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

首先,在我通常使用 SCOPE_IDENTITY() 的地方,使用 uniqueidentifier 不再可能,即使在概念上它仍然涉及作为默认值 (newid() 或newsequentialid()) 约束。

我决定在 INSERT 语句中使用 OUTPUT 子句将 UUID 输出到表变量。现在我想起来了,OUTPUT 子句使 SCOPE_IDENTITY 过时了,考虑到它是实现同样事情和更多事情的更清晰和更强大的方式(例如,为所有插入的行获得对多个自动生成的列的清晰和直接访问)。

但是,使用 OUTPUT 后,我现在想知道这会如何影响通常会在插入之后的 @@rowcount 测试。 @@rowcount 会反映主语句插入的行数还是输出子句插入表变量的行数?

您可能认为它不会产生影响(即计数应该相同),但它确实会产生影响,因为documentation 表示 OUTPUT 子句将返回值并填充表甚至如果插入语句失败。

具有 OUTPUT 子句的 UPDATE、INSERT 或 DELETE 语句将 即使语句遇到错误和 被回滚。如果发生任何错误,则不应使用结果 你运行语句。

它确实提到@@rowcount 特别是只有在使用 OUTPUT 时才会反映最外层的语句,但它提到这是嵌套查询的上下文。由于在我的例子中 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?

【问题讨论】:

  • Will the @@rowcount reflect the number of rows inserted in the main statement or the number of rows inserted into the table variable by the output clause? 不要做一个混蛋,但你试一试了吗?对于易于验证的内容,似乎有很多文章。
  • 如果经常写题思考问题;即使我可以/将/已经对其进行了测试并找到了答案,我还是为了社区而发布了这个问题,这样如果其他人遇到这种情况,这个记录可以帮助他们。同时,即使我通过实验验证了行为,也不能回答是否有更好的方法来获取值,或者是否有更好的方法来检查语句是否成功。问题实际上是关于如何最好地处理这个简单的任务,同时也展示了可能出现的复杂问题。
  • 有理有据,点个赞!
  • 重要的一点:你的引用说的文档“一个 OUTPUT 子句将返回行给 客户端 即使语句遇到错误并且被回滚。”请注意我对“client”的强调,如果您的 OUTPUTtable i>,然后它将与其他所有内容一起回滚,并且有效地,不会将新行添加到 OUTPUT 目标表中。

标签: tsql uniqueidentifier identity-column rowcount output-clause


【解决方案1】:

我已经通过以下 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 变量中存在零行,但请继续阅读,因为此结果具有误导性。

首先,这让我相信,由于没有插入任何行,因此不会发生 OUTPUT。这是错误的,一个简单的修改就证明了这一点。

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 反映了最终插入的行数,即为零,因为虽然前两个值已成功插入并输出到@uuidtable,但由于错误。

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

【讨论】:

    猜你喜欢
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 2017-05-11
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多