【问题标题】:Why does this stored procedure not return the correct ID?为什么这个存储过程没有返回正确的 ID?
【发布时间】:2010-08-06 14:24:37
【问题描述】:

这个存储过程会间歇性地返回一个数百万的 ID,而它实际上应该只有 400 左右。

set ANSI_NULLS OFF
set QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[TestStoredProcedure]
(
    @Title VARCHAR(50),
    @ID INT OUTPUT
)
AS

DECLARE @ResultsTable Table(InsertedID INT);

INSERT INTO Table 
(
    Title
)
OUTPUT INSERTED.ID INTO @ResultsTable
VALUES 
(
    @Title
);
SELECT @ID = (SELECT TOP 1 InsertedID FROM @ResultsTable);

这个存储过程曾经使用 SCOPE_IDENTITY() 返回 ID,但也有同样的问题。

数据库中没有触发器。只有 SQL Server 自动创建的主键上的索引。根本没有任何表的 ID 与返回的值一样大,所以我不知道这些大数字是从哪里来的。

任何帮助或建议将不胜感激。

编辑: 正如我上面所说,这个存储过程最初是这样使用 SCOPE_IDENTITY() 的:

set ANSI_NULLS OFF
set QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[TestStoredProcedure]
(
    @Title VARCHAR(50),
    @ID INT OUTPUT
)
AS

INSERT INTO Table 
(
    Title
)
VALUES 
(
    @Title
);
SELECT @ID = SCOPE_IDENTITY();

编辑 2:
确切的 SQL 版本是:
Microsoft SQL Server 2005 - 9.00.4230.00 (X64) 2009 年 7 月 30 日 13:42:21 版权所有 (c) 1988-2005 Microsoft Corporation Standard Edition (64-bit) o​​n Windows NT 5.2 (Build 3790: Service Pack 2)

编辑 3:
这就是存储过程的调用方式(旧的经典 ASP,它是一个遗留站点)

set obj_CMD = Server.CreateObject("ADODB.Command")
    with obj_CMD
        .ActiveConnection = Application("DSN")
        .CommandText = "TestStoredProcedure"
        .CommandType = adCmdStoredProc

        dim txt_title
        txt_title = "Some text"

        set oParam = .CreateParameter("@Title",adVarChar,adParamInput,50,txt_title)
        .Parameters.Append oParam       
        set oParam = .CreateParameter("@ID",adInteger,adParamOutput)
        .Parameters.Append oParam
        .Execute

        dim ID
        ID = .Parameters("@ID").Value

    end with
set obj_CMD = nothing

编辑 4:
运行 DBCC CHECKIDENT ('Table') 返回:

检查身份信息:当前身份值“422”,当前列值“422”。 DBCC 执行完成。如果 DBCC 打印错误消息,请联系您的系统管理员。

这符合预期。

【问题讨论】:

  • 我从来都不是“top 1”的粉丝。如果您使用 max(InertedID) 代替,您会遇到同样的问题吗?
  • 相当肯定@ResultsTable 是矫枉过正 - 应该能够在 OUTPUT 子句中设置@ID
  • 在表中你有插入发生时间的时间戳吗?如果是这样,您可以 SELECT TOP 1 AutoGeneratedID FROM Table ORDER BY timestampcolumn DESC
  • SQL 2005 的哪个版本(运行select @@version
  • @mpenrow - 这在多用户环境中不安全

标签: sql sql-server-2005 stored-procedures


【解决方案1】:

我认为问题在于你如何执行你的 sp。

declare @i int = 0

EXEC [TestStoredProcedure] '1', @i OUTPUT

select @i

也许你忘记了 OUTPUT 关键字...

编辑:如果是这样 - 使用 SCOPE_IDENTITY() 因为这是在您的情况下获取 id 值的更好方法。

【讨论】:

  • 该错误是间歇性的,因此没有像输出关键字这样的重大缺失。首次发生错误时我正在使用 SCOPE_IDENTITY() 并将其更改为问题中的代码作为尝试解决方法
  • 尝试执行 DBCC CHECKIDENT,也许你会得到一些额外的信息
【解决方案2】:

我的理解是,直到创建行之后才能确定分配给标识列的值,这包括尝试通过 OUTPUT 子句访问它。

@@identity 和 scope_identity() 确实应该有效。您可以使用该代码发布您的示例吗?

(旁注:当我说“我的理解是......”时,我的意思是我已经在多个版本的 SQL Server 中研究了很多很多,并且我已经从来没有找到一种方法来做到这一点,而且我似乎记得这些年来读过一些帖子和文章说这完全不能做到,但是嘿,我真的想错了,所以我会看这个发布。)

【讨论】:

  • 您可以使用 OUTPUT 子句访问新的 IDENTITY 值。但是,是的,SCOPE_IDENTITY() 应该可以完成这项工作。
  • 我从来没有遇到过使用这种方法返回身份的问题 - inserted 子句中的 inserted 表反映了插入的行,就像在触发器中一样 - 请参阅 MS 文档 - msdn.microsoft.com/en-us/library/ms177564.aspx .
  • 我知道,当 2005 年首次问世时,我在某处读到输出参数没有捕获标识列。也许我读错了,也许他们写错了,也许他们已经修好了。
猜你喜欢
  • 2012-04-10
  • 1970-01-01
  • 2020-03-13
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
  • 2014-06-18
  • 1970-01-01
相关资源
最近更新 更多