按名称动态获取存储过程参数

Posted

技术标签:

【中文标题】按名称动态获取存储过程参数【英文标题】:Obtaining stored procedure parameter dynamically by name 【发布时间】:2015-08-24 15:09:31 【问题描述】:

让我们创建一个存储过程,其中包含许多相同类型的相似输入参数:

CREATE PROCEDURE [dbo].[SampleStoredProcedure]
    @p1 NVARCHAR(MAX) = NULL,
    @p2 NVARCHAR(MAX) = NULL,
    @p3 NVARCHAR(MAX) = NULL,
    ...
    @p1000 NVARCHAR(MAX) = NULL

一开始,在程序内部,我想生成一个我应该使用的参数(字符串)列表,这取决于一些数据库数据。

例如,我有 1000 个参数,但我只想读取 10 个,并使用这些值执行一些 SQL 语句。

    是否可以通过参数名称作为字符串获取参数?任何动态 SQL 查询?

    也许有某种方法可以遍历所有输入参数并检查列表是否包含当前参数?

可以为每个参数单独生成带有某些条件的SQL,但是存储过程会很长,以后很难修改。可能性能也会比1.方法差。表值参数也是一种解决方案,但关键是要避免它,使用单独的参数。

总结: 我有一个字符串列表,定义了应该映射哪些输入参数,我只想忽略其他参数,以避免额外的条件。 SQL 查询应仅使用某些输入参数执行 - 由其他表中的上下文定义。

一些例子:

-- It will generate parameters' list - some context.
DECLARE MyCursor CURSOR
    LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
    SELECT [FieldName] FROM [Fields] AS [F] WHERE [F].[ProjectId] = @ProjectId

-- It will execute some action only for defined input parameters.
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO @FieldName
WHILE @@FETCH_STATUS = 0
BEGIN 
    -- It doesn't work, but it illustrates the problem.
    SET @FieldValue = N'@' + @FieldName
    EXEC sp_executesql @Query, @Params, @FieldName = @FieldName, @FieldValue = @FieldValue
    FETCH NEXT FROM MyCursor INTO @Field
END
CLOSE MyCursor
DEALLOCATE MyCursor

【问题讨论】:

你的目标是什么?为什么要愿意有这么多参数?有要求吗?这是一个你可以解释的选择吗? 在核心查询中我需要获取值,但动态使用参数名称。 您需要使用参数名称获取值:这就是它的工作方式。您按名称调用参数,然后使用它。也许您可以向我们展示一些程序中的代码以及您面临的问题。 您的问题太模糊了,无法提供可靠的答案。 1,000 个参数尖叫着非常糟糕的设计。如果您能解释您的程序需要做什么,我们可以提供帮助。 我有一些包含许多字段的实体框架对象。但通常只有某些字段可以包含指定实例的值,这取决于某些鉴别器字段。所以,我正在尝试使用这个存储过程来映射EF实体,但我不想一一映射参数,因为SP会很丑。 【参考方案1】:

这将返回给定存储过程的所有参数的名称

 SELECT
    p.name
    ,p.max_length
FROM
    sys.all_objects o
JOIN
    sys.all_parameters p
ON
    o.object_id = p.object_id
WHERE
    o.name = 'myStoredProcedure'  -- name of stored procedure

【讨论】:

不幸的是我想在过程中使用参数值。更重要的是,我知道要使用哪个名称,但不能使用这样的名称:SET value = N'@' + @paramName @Kryszal,您可以考虑将您的设计从存储过程中的 1000 参数更改为表值参数。然后,也许可以按照你想要的方式做 是的,你是对的,这也将是一些解决方案。但在这种情况下,我不能使用实体框架映射(插入/更新存储过程的实体参数和输入参数之间)。最终,将需要实现一些自定义逻辑来处理它。【参考方案2】:

如果我们假设您的参数(不是 TVP)具有已知名称(这可以使用 DMV 和 Dynamic-SQL 动态完成),您可以使用一些解决方法,例如:

1) 为自身创建链接服务器

2) 使用OPENQUERY查询自身

你的:

-- It doesn't work, but it illustrates the problem.
SET @FieldValue = N'@' + @FieldName

将是:

SELECT @FieldValue = 
    (SELECT * FROM OPENQUERY('loopback_servername','SELECT ' + @FieldName))

【讨论】:

以上是关于按名称动态获取存储过程参数的主要内容,如果未能解决你的问题,请参考以下文章

用于获取表名、视图和存储过程的 SQL 语句,按模式排序

以列名作为输入参数的存储过程中的动态 sql

oracle中怎么执行带有输出参数的存储过程,在程序中我知道怎么调用,

存储过程中动态执行SQL并获取返回结果

无法获取 SP 的动态执行以返回 INOUT 参数

如何使用多个输出参数执行存储过程?