【问题标题】:Calling a stored proc that returns a recordset from within a stored proc调用从存储过程中返回记录集的存储过程
【发布时间】:2010-09-16 21:31:29
【问题描述】:

在 SQL Server 2005 中工作,我有一个存储过程,它插入一条记录并通过 SELECT @@IDENTITY 返回新 ID;作为最后一个命令。

然后我想从另一个存储过程中调用它,并获取新 ID 的值。

但我不知道如何获取第一个过程返回的值。

例子:

CREATE PROCEDURE spMyInsert(@Field1 VARCHAR(10)) AS 
BEGIN

    INSERT INTO tMyTable (Column1) VALUES (@Field1); // ID column implicitly set

    SELECT @@IDENTITY ID;

END


CREATE PROCEDURE spMyMain AS
BEGIN

    DECLARE @NewID INT;

    EXEC spMyInsert 'TEST';

    // How do I set @NewID to the value returned from spMyInsert?

END

还有另一个question 几乎回答了我的问题,但不完全是。这解释了如何将结果插入到另一个表中,但我要做的只是将它存储在一个局部变量中。

查看其他类似的问题,一般的答案是更改为设置 OUTPUT 变量或创建一个函数来执行此操作,但在我的情况下我不能这样做,因为其他 .NET 数据访问的东西使用相同的存储proc,我也不想将存储的 procs 的所有工作都复制为函数。

我尝试过但都失败的几件事是:

SET @NewID = (EXEC spMyInsert 'TEST');

SET @NewID = (SELECT ID FROM (EXEC spMyInsert 'TEST'));

有人知道怎么做吗?

谢谢, 本

【问题讨论】:

  • 为什么不想使用OUTPUT参数呢?对于返回标量值,这些是最佳选择。如果您只是想避免更改调用同一过程的现有代码,则可以为参数设置默认值。
  • 从人们在这篇文章中留下的 cmets 中可以清楚地看出,对于我确实需要使用 OUTPUT 参数的其他问题。我会看看改变这一切所需的努力。我的问题是有一些我不想破坏的依赖关系!
  • +1 投票给所有建议 SCOPE_IDENTITY 而不是 @@IDENTITY 的人!!

标签: sql-server stored-procedures


【解决方案1】:

顺便说一下,您可能应该检查@@identity 是您需要的,而不是scope_identity

如果它你需要的,那么它仍然可以在调用存储过程中访问。

CREATE PROCEDURE spMyMain 
AS
BEGIN
    DECLARE @NewID INT;

    EXEC spMyInsert 'TEST';

    SET @NewID = @@IDENTITY

    SELECT @NewID AS '@NewID'

END

如果您使用scope_identity 并且不想使用输出参数或过程返回码,则需要应用的更通用的解决方案是

CREATE PROCEDURE spMyMain AS
BEGIN

 DECLARE @NewID INT;

    DECLARE @IdHolder TABLE
    (
    id INT
    )

    INSERT INTO @IdHolder
    EXEC spMyInsert 'TEST';

    IF @@ROWCOUNT<>1
    RAISERROR('Blah',16,1)

     SELECT @NewID = id FROM @IdHolder

END

【讨论】:

  • 我也考虑过这样做,但认为这不是一种非常优雅的方式。另外,感谢 scope_identity 提醒!
【解决方案2】:

首先,不要使用@@IDENTITY,而是使用SCOPE_IDENTITY()(搜索此站点或Google 以了解原因)。然后只需在输出参数中返回值:

CREATE PROCEDURE spMyInsert(@Field1 VARCHAR(10), @NewID int output) AS  
BEGIN 
    INSERT INTO tMyTable (Column1) VALUES (@Field1);
    SET @NewID = scope_identity();
END 
 go

CREATE PROCEDURE spMyMain AS 
BEGIN 
     DECLARE @NewID INT; 
     EXEC spMyInsert @Field1 = 'TEST', @NewID = @NewID OUTPUT; 
END
go

【讨论】:

  • OP 在问题中说他们不想使用输出参数。不清楚为什么,但实际上。
  • 好点,我显然没有仔细阅读。我也不知道为什么,但大概真正的过程实际上更复杂。当然,没有理由不同时使用结果集和输出参数。
  • 谢谢,显然有很多理由使用 OUTPUT 参数而不是这样做。问题是我有一些我不想打破的依赖关系。另外,感谢您提供有关 SCOPE_IDENTITY 的信息!
【解决方案3】:

这里的问题是 spMyInsert 返回一个 Select。当您执行spMyMain 时,它将返回从spMyInsert 选择,然后从spMyMain 选择选择

我建议您修改spMyInsert 以使用OUTPUT 参数

CREATE PROCEDURE spMyInsert(@Field1 VARCHAR(10), @NewId int output) AS 
BEGIN

    INSERT INTO tMyTable (Column1) VALUES (@Field1); // ID column implicitly set

    SELECT @NewId = @@SCOPE_IDENTITY;

END

然后

CREATE PROCEDURE spMyMain AS
BEGIN

    DECLARE @NewID INT;
Set @NewId = 0

    EXEC spMyInsert 'TEST', @NewId output;

select @NewId
    // How do I set @NewID to the value returned from spMyInsert?

END

请注意,我还将@@Identity 更改为@@scope_identity 最好使用@@Scope_Identity,因为这将返回适用于当前连接的新ID。

【讨论】:

  • 谢谢,很明显我需要开始使用 OUTPUT 参数。并感谢 SCOPE_IDENTITY 提醒。
【解决方案4】:

试试这个:

Execute @NewID = spMyInsert 'TEST'

编辑:在更彻底地阅读了他的问题并意识到他正在处理选择而不是返回之后:您可以将该过程包装在函数调用中然后调用该函数吗?

select @NewId = from fnMyInsert('TEST')

【讨论】:

  • 这将获得spMyInsert 的返回值,而不是SELECT 输出(如果spMyInsert 可以更改为使用返回码用于该目的,则可能是需要的。)。
  • 啊,你是对的。我没有仔细阅读这个问题。我在想这是一个回报。
  • 谢谢,这是我一直在寻找的答案。我已经对其进行了测试并且它可以工作,尽管它具有在调用外部存储过程时返回两个选择的结果的副作用,这将导致其他问题。所以我想我会像大多数人建议的那样重新设计它以使用 OUTPUT 参数。谢谢!
  • @Wix:我在看到你认为这是回报的评论之前写了那条评论……但我已经测试过了,它确实有效!
  • 除非你有一个return 并且不适合我,否则它不应该工作。 declare @NewID int Execute @NewID = spMyInsert 'TEST' select @NewID 总是返回 0。
【解决方案5】:

一个输出参数是要走的路,但如果你真的不能改变内部SP,那么正如你所说,你可以让内部SP将其结果返回到一个表中,然后从那里取出值。

例如。

declare @NewID int,
@Customer table(CustomerId int);

insert into @Customer
exec spMyInsert 'TEST';

select @NewID = CustomerId from @Customer;

【讨论】:

  • 嗯……就像马丁·史密斯说的那样
猜你喜欢
  • 1970-01-01
  • 2017-05-06
  • 1970-01-01
  • 2019-04-20
  • 2013-09-01
  • 2014-01-04
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多