我们什么时候使用存储过程和输出参数?

时间:2018-02-17 12:38:46

标签: sql-server tsql stored-procedures

我们何时使用带有输出参数的存储过程?何时使用不带参数的存储过程?

我的问题基于一个例子:

带输出参数的存储过程

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

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

3 个答案:

答案 0 :(得分:0)

一个例子,基于你的例子,如果你引入了对查询的分页。

因此,结果集约束为10个项目,并使用总计数输出参数来驱动屏幕上网格的分页。

答案 1 :(得分:0)

基本上,您看到的结果实际上是您在程序结束时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参数。假设您的存储过程没有返回任何内容,它更像是对数据库的命令,但您仍然需要一种消息,或者更具体地说是一个值。拿这两个例子:

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

这些只是虚拟的例子,但只是为了让这个想法更清晰。

答案 2 :(得分:0)

来自ozz的关于分页的回答没有意义,因为没有输入参数对返回的记录数量实施约束。

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