5

是否可以动态地向 sp_ExecuteSql 提供参数列表?

在 sp_ExecuteSql 中,查询和参数定义是字符串。我们可以为这些使用字符串变量,并传入我们想要执行的任何查询和参数定义。但是,在为参数赋值时,我们似乎不能使用字符串或字符串变量作为参数名称。

例如:

DECLARE @SelectedUserName NVARCHAR(255) ,
    @SelectedJobTitle NVARCHAR(255);
SET @SelectedUserName = N'TEST%';
SET @SelectedJobTitle = N'%Developer%';

DECLARE @sql NVARCHAR(MAX) ,
    @paramdefs NVARCHAR(1000);
SET @sql = N'select * from Users where Name LIKE @UserName '
    + N'and JobTitle LIKE @JobTitle;'
SET @paramdefs = N'@UserName nvarchar(255), @JobTitle nvarchar(255)';
EXEC sp_ExecuteSql @sql, @paramdefs, @UserName = @SelectedUserName,
    @JobTitle = @SelectedJobTitle;

查询@sql 和参数定义@paramdefs 可以作为字符串变量动态传递到sp_ExecuteSql。但是,在我看来,在为参数赋值时,我们不能动态赋值,并且必须始终提前知道参数的数量及其名称。请注意,在我的示例中,我如何动态声明参数 @UserName 和 @JobTitle 并将该声明作为字符串变量传递,但是当我想设置参数名称时,我必须显式指定它们。有没有办法绕过这个限制?

我希望能够动态声明参数并动态分配给它们。就像是:

EXEC sp_ExecuteSql @sql, @paramdefs,
    N'@UserName = @SelectedUserName, @JobTitle = @SelectedJobTitle';

请注意,这实际上不起作用,但说明了我希望发生的事情。如果这种事情有效,那么我可以传递具有不同名称的不同数量参数的不同查询。整个事情将是动态的,我不必事先知道参数的名称或数量。

4

5 回答 5

5

您可以通过使用表值参数作为唯一参数来执行此操作:

DECLARE @YourQuery NVARCHAR(MAX0 = '<your dynamic query>'

CREATE TYPE dbo.SqlVariantTable AS TABLE
(
    [Name]  VARCHAR(255),
    Type    VARCHAR(255),
    Value   SQL_VARIANT
)

DECLARE @Table SqlVariantTable;

-- Insert your dynamic parameters here:
INSERT INTO @Table 
VALUES
    ('Parameter1', 'VARCHAR(255)', 'some value'),
    ('Parameter2', 'INT', 3),

DECLARE @ParameterAssignment NVARCHAR(MAX)
SELECT @ParameterAssignment = ISNULL(@ParameterAssignment + ';','') + 'DECLARE ' + Name + ' ' + Type + ' = (SELECT CAST(Value AS ' + Type + ') FROM @p1 WHERE Name = ''' + Name + ''')'
FROM @Table

SET @YourQuery = @ParameterAssignment + ';' + @YourQuery

EXEC SP_EXECUTESQL @YourQuery, N'@p1 SqlVariantTable READONLY', @Table

现在您可以简单地将参数插入到@Table 变量中,它们将以其原始名称和类型出现在 SP_EXECUTESQL 中执行的查询中。只需确保不使用 VARCHAR(MAX) 或 NVARCHAR(MAX) 变量类型,因为 SQL_VARIANT 不支持它们。使用(例如) VARCHAR(4000) 代替

于 2020-04-20T11:12:41.947 回答
3

您正在尝试在抽象级别上工作太高。

任意参数需要动态 SQL,也就是通过字符串构建 SQL,这使得参数的整个意义没有实际意义。

相反,这应该在调用代码(例如 C#)中作为参数处理,这允许您在字符串中获取任何 SQL 语句,应用任意数量的参数并执行它。

于 2013-08-30T06:24:58.777 回答
3

我也想过这个,找不到比这更好的了:

BEGIN
  DECLARE
    @p1 int, @p2 int, @p3 int, @p4 int...;

  DECLARE
    @DynamicSQL NVARCHAR(MAX);

  SET
    @p1 = {some logic},
    @p2 = {some different logic},
    @p3 = {another logic},
    @p4 = {yet another logic},
    ...;
  
  
  SET
    @DynamicSQL =
    N'
      some statement
      doing
      somethin
      WHERE
        someColumn = @p1
        AND someAnotherColumn = @p2
        /*no more parameters used below this line*/
    ';

  exec sp_executesql
    @stmt = @DynamicSQL,
    @params = '@p1 int, @p2 int, @p3 int, @p4 int...'
    @p1 = @p1, @p2 = @p2, @p3 = @p3, @p4 = @p4, ...
END;

请注意,@DynamicSQL它只使用了 4 个可能参数中的 2 个。参数@p1 int, @p2 int, @p3 int, @p4 int...表示您可以在@DynamicSQL.

您必须有一个可以使用的预定义的最大参数数量,并且您@DynamicSQL只使用其中的一些子集来构建语句。语句中@params不存在的定义的参数将被忽略。@stmt

它不是 100% 通用的,但我猜使用 200 多个动态参数会产生代码异味。

于 2020-01-08T21:29:07.517 回答
2

虽然这不能回答我的问题,但我认为它可能对处于类似情况的其他人有用。我发现了以下内容:

如果您有固定数量的参数但不知道它们的名称,您可以通过位置而不是名称来传递参数值。以下将起作用:

exec sp_ExecuteSql 
    @sql, 
    @paramdefs, 
    @SelectedUserName, @SelectedJobTitle;

或者

exec sp_ExecuteSql 
    @sql, 
    @paramdefs, 
    N'TEST%', N'%Developer%';
于 2013-08-30T23:40:31.623 回答
0

请试试这个。

Declare @UName varchar(50)
Declare @Job varchar(50)
Set @UName = 'TEST%'
Set @Job = '%Developer%'
exec sp_ExecuteSql @sql, @paramdefs, @UserName = @UName, @JobTitle = @Job;

愿这对你有所帮助。

参考来自technet.Microsoft.com

前任。

DECLARE @IntVariable int;
DECLARE @SQLString nvarchar(500);
DECLARE @ParmDefinition nvarchar(500);

/* Build the SQL string one time.*/
SET @SQLString = N'SELECT BusinessEntityID, NationalIDNumber, JobTitle, LoginID
                   FROM AdventureWorks2012.HumanResources.Employee 
                   WHERE BusinessEntityID = @BusinessEntityID';
SET @ParmDefinition = N'@BusinessEntityID tinyint';

/* Execute the string with the first parameter value. */
SET @IntVariable = 197;
EXECUTE sp_executesql @SQLString, @ParmDefinition,
                      @BusinessEntityID = @IntVariable;

/* Execute the same string with the second parameter value. */
SET @IntVariable = 109;
EXECUTE sp_executesql @SQLString, @ParmDefinition,
                      @BusinessEntityID = @IntVariable;

对于动态,你必须通过这样的东西

EXECUTE sp_executesql N'Select * from Admin WHERE ID = @ID and FirstName=@FName',
                      N'@ID tinyint, @FName varchar(250)',
                      @ID = 2, @FName = 'admin';
于 2013-08-30T04:34:06.750 回答