【问题标题】:When exactly do we use stored procedures with output parameters?我们究竟什么时候使用带有输出参数的存储过程?
【发布时间】:2018-02-17 12:38:46
【问题描述】:

我们究竟什么时候使用带输出参数的存储过程,什么时候使用不带参数的存储过程?

我的问题基于一个例子:

带输出参数的存储过程

CREATE PROCEDURE uspGetContactsCountByCity
    @City nvarchar(60),
    @ContactsCount int OUT
AS
BEGIN
    SELECT @ContactsCount = COUNT(ContactID) 
    FROM Contacts
    WHERE City = @City
END

存储过程执行

DECLARE @ContactsTotal INT

EXEC uspGetContactsCountByCity @ContactsCount = @ContactsTotal OUT, @city = 'Berlin'
SELECT @ContactsTotal

结果:2

没有输出参数的存储过程

CREATE PROCEDURE uspGetContactsCountByCity2
    @City nvarchar(60)
AS
BEGIN
    SELECT COUNT(ContactID) 
    FROM Contacts
    WHERE City = @City
END

存储过程执行:

EXEC uspGetContactsCountByCity2 @city = 'Berlin'

结果:2

两个过程以相同的形式返回相同的结果,那么有什么区别?

【问题讨论】:

  • 旁白:为了增加乐趣,一个存储过程可以返回多个结果集,例如GetCustomerOrder( @OrderId ) 可以返回带有订单标题的结果集和带有订单行项目的第二个结果集。如果在输出参数中返回客户的信用等级是有意义的,那很好。酌情混合搭配。

标签: sql-server tsql stored-procedures


【解决方案1】:

基本上,您看到的结果实际上是您在过程结束时SELECT 的结果,它正在做同样的事情。

请看一下这个documentation

如果在过程定义中为参数指定了 OUTPUT 关键字,则存储过程可以在存储过程退出时将参数的当前值返回给调用程序。要将参数的值保存在调用程序可以使用的变量中,调用程序在执行存储过程时必须使用 OUTPUT 关键字。

所以基本上如果你希望你的存储过程只返回一个值而不是一个数据集,你可以使用输出参数。例如,让我们以您给出的程序为例。他们都做同样的事情,这就是你得到相同结果的原因。但是在第一个具有输出参数的过程中稍微改变一下呢? 这是一个例子:

create table OutputParameter (
    ParaName varchar(100)
)

insert into OutputParameter values ('one'), ('two'),('three'),('one')

CREATE PROCEDURE AllDataAndCountWhereOne
    @name nvarchar(60),
    @count int OUT
    as
    Begin
    SELECT @count = COUNT(*) from OutputParameter
    Where ParaName = @name

    select Distinct(ParaName) from OutputParameter
End

Declare @TotalCount int
Exec AllDataAndCountWhereOne @count = @TotalCount OUT, @name = 'One'
Select @TotalCount

在此示例中,您将获取表中所有不同的存储数据,以及给定名称的计数。

ParaName
--------------------
one
three
two

(3 row(s) affected)


-----------
2

(1 row(s) affected)

这是使用输出参数的一种方式。在获得初始数据集后,您无需进行额外查询即可获得不同的数据和所需的计数。

最后,回答你的问题:

这两个过程以相同的形式给我们相同的结果,那么有什么区别?

你自己的结果没有改变,这就是你没有真正注意到差异的原因。

其他例子:

您可以在其他类型的过程中使用OUT 参数。假设您的存储过程不返回任何内容,它更像是对 DB 的命令,但您仍然想要返回一种消息,或者更具体地说是一个值。举两个例子:

CREATE PROCEDURE InsertDbAndGetLastInsertedId
    --This procedure will insert your name in the database, and return as output parameter the last inserted ID.
    @name nvarchar(60),
    @LastId int OUT
    as
    Begin
    insert into OutputParameterWithId values (@name); 
    SELECT @LastId = SCOPE_IDENTITY()
End

或:

CREATE PROCEDURE InsertIntoDbUnlessSomeLogicFails
    --This procedure will only insert into the db if name does exist, but there's no more than 5 of it
    @name nvarchar(60),
    @ErrorMessage varchar(100) OUT
    as
    Begin
    set @ErrorMessage = ''

    if ((select count(*) from OutputParameterWithId) = 0)
    begin
        set @ErrorMessage = 'Name Does Not Exist'
        return
    end

    if ((select count(*) from OutputParameterWithId) = 5)
    begin
        set @ErrorMessage = 'Already have five'
        return
    end

    insert into OutputParameterWithId values (@name); 
End

这些只是虚拟示例,只是为了让概念更清晰。

【讨论】:

  • 好吧,现在开始说得通了,但是带和不带输出参数的存储过程之间的界限似乎真的很薄
  • 好吧,这一切都取决于您喜欢如何使用它。例如,您也可以在其他类型的查询中使用它。假设您只想插入或更新,或者实际上在您的 SP 中有一些逻辑(我不喜欢),我将编辑我的答案以提供这样的示例。
  • 好的,但是输出参数到底给了我们什么?我的意思是好的,不带输出参数的 SP 会返回给我们一些结果或值,而带输出参数的 SP 会给我们一些变量——我们可以稍后在我们的代码/另一个过程中实际使用它们吗?
  • 是的,它只是一个SP会返回的值,你可以用它来指导你的程序的流程,或者只是从中获取信息,正如我之前所说,这取决于如何做如果需要,您想使用它。
  • 首先,最好编辑你的评论,这样的话在 SO 中是不受欢迎的。其次,如果它适合您并回答您的问题,请始终确保接受它。 (可能是这个或任何其他答案。)欢迎来到 Stackoverflow。
【解决方案2】:

如果您在查询中引入了分页,则基于您的示例。

因此结果集被限制为 10 个项目,并且您使用总计数参数来驱动屏幕网格上的分页。

【讨论】:

  • 什么?我真的不明白。我之前运行过这两个查询,它们都给了我与我在问题中写的相同的结果
  • 只是做事方式不同而已。你想多了。在我的示例中,我建议存储过程返回结果集,输出 var 返回总计数。
【解决方案3】:

ozz 关于分页的回答没有意义,因为没有输入参数对返回的记录数实施限制。

但是,要回答这个问题……这些存储过程返回的结果是不一样的。第一个在 out 参数 ContactsCount 中返回给定城市的联系人记录数。虽然也可以通过检查 reader.Rows.Count 在第二个工具中接收计数,但实际记录也是可用的。首先,不返回任何记录 - 只返回计数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-31
    • 2011-08-19
    • 1970-01-01
    • 2014-09-09
    • 2023-02-25
    • 2021-08-03
    • 1970-01-01
    • 2011-05-03
    相关资源
    最近更新 更多