考虑以下 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
参数传入?
其实有一个很简单的方法!
通过设置默认值使参数可选(@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 值的默认值。
您可以通过查询系统视图来完成此操作:
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 中的数据库树: [数据库] -> 可编程性 -> 存储过程 -> [过程] -> 参数
也许我错了,但我不相信这是可能的。 OUTPUT 是存储过程定义的一部分,因此您应该知道参数何时为 OUTPUT。没有办法动态设置它,所以我认为通过代码确定参数何时输出是没有意义的,因为你已经知道了。
如果您正在尝试编写动态代码,Piotr Lasota 的答案应该会引导您找到正确的方法来实现参数何时为输出。
------ 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)
使用以下查询获取所有参数的名称并检查它是否是输出参数:
select name, is_output from sys.parameters
您可以在调用过程时强制查询使用全局变量@@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