T-SQL 存储过程 - 检测参数是否作为 OUTPUT 提供

问题描述 投票:0回答:6

考虑以下 T-SQL 代码片段:

CREATE PROC dbo.SquareNum(@i INT OUTPUT)
AS
BEGIN
    SET @i = @i * @i
    --SELECT @i
END
GO

DECLARE @a INT = 3, @b INT = 5
EXEC dbo.SquareNum @a OUTPUT
EXEC dbo.SquareNum @b
SELECT @a AS ASQUARE, @b AS BSQUARE
GO
DROP PROC dbo.SquareNum

结果集为:

ASQUARE     BSQUARE
----------- -----------
9           5

可以看出,

@b
没有平方,因为它没有作为输出参数传入(传入参数时没有
OUTPUT
限定符)。

我想知道是否有一种方法可以在存储过程主体(本例中为 dbo.SquareNum 主体)中进行检查,以查看参数是否确实已作为

OUTPUT
参数传入?

sql-server t-sql stored-procedures output-parameter
6个回答
1
投票

其实有一个很简单的方法!

通过设置默认值使参数可选(@Qty AS Money = 0 下面)

然后,在调用过程时传递默认值以外的值。然后立即测试该值,如果它不是默认值,则说明该变量已通过。

Create Procedure MyProcedure(@PN AS NVarchar(50), @Rev AS NVarchar(5), @Qty AS Money = 0 OUTPUT) AS BEGIN
DECLARE @QtyPassed AS Bit = 0
IF @Qty <> 0 SET @QtyPassed = 1

当然,这意味着该变量不能用于除 OUTPUT 以外的任何用途,除非您有一个您知道永远不会用作 INPUT 值的默认值。


0
投票

您可以通过查询系统视图来完成此操作:

select 
    p.name as proc_name,
    par.name as parameter_name,
    par.is_output
from sys.procedures p
inner join sys.parameters par on par.object_id=p.object_id
where p.name = 'SquareNum'

或检查 Management Studio 中的数据库树: [数据库] -> 可编程性 -> 存储过程 -> [过程] -> 参数


0
投票

也许我错了,但我不相信这是可能的。 OUTPUT 是存储过程定义的一部分,因此您应该知道参数何时为 OUTPUT。没有办法动态设置它,所以我认为通过代码确定参数何时输出是没有意义的,因为你已经知道了。

如果您正在尝试编写动态代码,Piotr Lasota 的答案应该会引导您找到正确的方法来实现参数何时为输出。


0
投票
   ------ THIS WILL GIVE YOU THE BOTH VALUE IN squared------

    CREATE PROC dbo.SquareNum(@i INT OUTPUT)
    AS
    BEGIN
        SET @i = @i * @i
        --SELECT @i
    END
    GO

    DECLARE @a INT = 3, @b INT = 5
    EXEC dbo.SquareNum @a OUTPUT
    EXEC dbo.SquareNum @b OUTPUT
    SELECT @a AS ASQUARE, @b AS BSQUARE
    GO
    DROP PROC dbo.SquareNum


  -----TO CHECK STORED PROCEDURE BODY-----

    SELECT OBJECT_NAME(object_id), 
           OBJECT_DEFINITION(object_id)
    FROM  sys.procedures
    WHERE OBJECT_DEFINITION(object_id) =(SP_NAME)

0
投票

使用以下查询获取所有参数的名称并检查它是否是输出参数:

select name, is_output from sys.parameters

0
投票

您可以在调用过程时强制查询使用全局变量@@PROCID,然后在调用过程后检查文本中是否至少有一个“

OUT

它不会检查参数是否使用

OUTPUT
语句,仅当查询文本中包含该单词时,才“记住”谁正在编写新代码

弱点:通过使用此功能,您无法在不处于另一个过程或触发器中的情况下调用查询中的过程

CREATE OR ALTER PROC TEST (@I INT OUT, @PROCID INT) AS BEGIN
    
        --Get the code that is calling this procedure
    
    DECLARE @Q VARCHAR(MAX)=(
        SELECT
            OBJECT_DEFINITION(OBJECT_ID)
        FROM SYS.ALL_OBJECTS
        WHERE OBJECT_ID = @PROCID)

        --Check if exists any code, if is null it means the user called in a query and testing

    IF @Q IS NULL
        THROW 50000, 'When calling procedure "TEST" you must specify parameter @PROCID = @@PROCID and call the procedure through another procedure or trigger', 1

        --Check if has the OUT word after the name of the procedure

    IF @Q NOT LIKE '%TEST%OUT%'
        THROW 50000, 'When calling procedure "TEST" the parameter "@I" must have the OUTPUT statement', 1

    PRINT 'code of the procedure here....'
END

调用示例:

EXEC TEST 10, null      --> Null shows FIRST message
EXEC TEST 10, 10        --> Random number shows FIRST message
EXEC TEST 10, @@PROCID  --> Right command but not in a procedure shows FIRST message

用另一个程序测试:

CREATE OR ALTER PROC TEST_2 AS BEGIN
    
    EXEC TEST 10, @@PROCID  --> Right command AND inside a procedure shows SECOND message
END
GO
EXEC TEST_2

正确方法:

CREATE OR ALTER PROC TEST_2 AS BEGIN
    
    DECLARE @I INT = 10
    EXEC TEST @I OUT, @@PROCID  --> Now the code executes...
END
GO
EXEC TEST_2

如何避免使用 OUT:

CREATE OR ALTER PROC TEST_2 AS BEGIN
    
    DECLARE @I INT = 10
    EXEC TEST @I, @@PROCID
    --OUT --> Sadly, this way works too, because the word OUT exists and it is after the name of the procedure
END
GO
EXEC TEST_2
© www.soinside.com 2019 - 2024. All rights reserved.