将存储过程参数值传递给嵌套存储过程,而不知道参数名称

时间:2014-04-22 15:21:11

标签: sql stored-procedures error-handling sql-server-2012

我正在尝试创建一个在所有存储过程中调用的通用错误捕获存储过程,我需要获取所有参数名称(我可以从知道存储过程名称的系统表中执行此操作)和值。

值是我真正需要获取并动态获取的值(无需通过名称将它们专门传递给存储过程)。

有没有办法将一个唯一的ID或其他东西传递给嵌套的存储过程,我可以使用它来获取嵌套存储过程中主存储过程的参数值?

简短示例:我有一个存储过程:

create PROCEDURE testParamaters
    @text1 VARCHAR(500),
    @DateTime1 DATETIME
AS

-- I want to be able to call an SP something like this:
EXEC DynamicErrorTrackingSP (pass something, system variable/data/etc, so I can 
                             dynamically get all parameter values in nested SP)

我目前有类似的代码,它工作正常(但必须为每个SP编辑以正确传递参数值(我不想为每个SP编辑它)。

EXEC DynamicErrorTrackingSP @ParmaterNameValuePairs = 
     '@text1 = ' + @text1 + ', @DateTime1 = ' + cast(@DateTime1 as varchar(500)) + ''

1 个答案:

答案 0 :(得分:0)

<强> TL; DR
只有当有人找到从其名称中获取变量值的方法时。

<强>答案
可以创建类型表的新数据类型,并将其用作错误跟踪存储过程的输入。在该变量中,每个参数都有一行,其名称和值 一个例子是

CREATE TYPE _stored_param AS TABLE (
  Name varchar(50)
, [Value] sql_Variant
)
GO

CREATE PROCEDURE printParam (@sentParam _stored_param READONLY) AS
BEGIN
  SELECT * FROM @sentParam
END
GO

CREATE PROCEDURE myProcedure (@param VARCHAR(10)) AS
BEGIN
  DECLARE @myParam AS _stored_param;

  INSERT INTO @myParam (Name, [Value]) VALUES ('@param', @param)
  EXEC printParam @myParam;
END
GO

EXEC myProcedure 'foo'

执行myProcedure的结果,完成最后一行将为您提供

Name    Value
------- -------
@param  foo

酷! ...但INSERT是静态的,每次更改或添加存储过程参数时,INSERT也需要更改。

我们可以更改创建动态INSERT的过程,使用INFORMATION_SCHEMA.PARAMETERSOBJECT_NAME(@@PROCID)条件中使用WHERE获取参数名称,只获取一个目前的程序。

初始SP

CREATE PROCEDURE Inception (@param1 VARCHAR(10), @param2 INT)
AS
BEGIN
  DECLARE @paramQuery as NVARCHAR(MAX);
  DECLARE @paramVar as _stored_param;
  DECLARE @execVar as NVARCHAR(MAX);

  SET @paramQuery = '';
  SELECT   @paramQuery 
        += 'SELECT ''' + PARAMETER_NAME 
         + ''', CAST(' + PARAMETER_NAME + ' AS SQL_VARIANT) UNION ALL '
  FROM     INFORMATION_SCHEMA.PARAMETERS
  WHERE    SPECIFIC_NAME = OBJECT_NAME(@@PROCID)
  ORDER BY ORDINAL_POSITION

  SET @paramQuery = LEFT(@paramQuery, len(@paramQuery) - 10);

  SET @execVar = ''
  SELECT   @execVar 
        += PARAMETER_NAME + ' ' + DATA_TYPE 
         + ISNULL('(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + '), ', ', ')
  FROM     INFORMATION_SCHEMA.PARAMETERS
  WHERE    SPECIFIC_NAME = OBJECT_NAME(@@PROCID)
  ORDER BY ORDINAL_POSITION

  SET @execVar = LEFT(@execVar, LEN(@execVar) - 1);

  INSERT INTO @paramVar
  EXEC sp_executesql @paramQuery, @execVar, @param1, @param2

  SELECT * from @paramVar
END
GO

EXEC Inception 'foo', 2;

在此存储过程中,变量@paramQuery被计算为字符串

SELECT '@param1', CAST(@param1 AS SQL_VARIANT) 
UNION ALL 
SELECT '@param2', CAST(@param2 AS SQL_VARIANT)

但作为动态查询,需要执行。

执行动态查询就像调用另一个存储过程一样:您需要在需要时传递参数,并且执行处于隔离级别,并且具有自己的本地参数,其中调用者变量不可见。
这意味着要执行查询以获取参数值,您需要将参数值作为参数传递 唯一的优点是当更改存储过程时更改参数编号,查询将生成错误,如

Msg 8178, Level 16, State 1, Line 39
The parameterized query '(@param1 varchar(10), @param2 int)SELECT '@param1', CAST(@param1' expects the parameter '@param2', which was not supplied.

要求检查sp_executesql参数段落。

使用参数的名称和值创建字符串或使用参数的名称和值创建XML的其他方法将触及相同的墙:获取变量的值,将其名称作为字符串(varchar)