是否可以动态提供sp_ExecuteSql参数名称?

时间:2013-08-30 04:09:51

标签: sql sql-server tsql

是否可以动态地向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';

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

5 个答案:

答案 0 :(得分:3)

你试图在抽象中工作得太高。

任意参数需要动态SQL,a.k.a。通过字符串构建SQL,然后使整个参数点无法实现。

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

答案 1 :(得分:3)

您可以通过使用表值参数作为唯一参数来做到这一点:

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)

答案 2 :(得分:2)

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

如果您有一定数量的参数但不知道它们的名称,则可以按位置而不是名称传递参数值。以下内容适用:

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

exec sp_ExecuteSql 
    @sql, 
    @paramdefs, 
    N'TEST%', N'%Developer%';

答案 3 :(得分:2)

我也考虑过这一点,找不到比这更好的东西了:

exec sp_executesql
  @stmt = N'blah blah WHERE C1 = @p1 AND C2 = @p2'
  @params = '@p1 int, @p2 int, @p3 int, @p4 int...'
  @p1 = @p1, @p2 = @p2, @p3 = @p3, @p4 = @p4, ...

请注意,在@stmt中仅使用了2个参数,但是有许多已定义和提供的参数。您必须给定可以使用的参数数量,但是只能使用所需的参数来构建查询语句。 @params参数中的定义与稍后提供的参数匹配,但是在语句中不存在,因此基本上可以忽略它们。然后,您可以动态填充这些参数。

它不是100%通用的,但不少于60%通用的。

答案 4 :(得分:0)

请试一试。

  

声明@UName varchar(50)

     

声明@Job varchar(50)

     

设置@UName ='TEST%'

     

设置@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);

     

/ *一次构建SQL字符串。* /

     

SET @SQLString = N'SELECT BusinessEntityID,NationalIDNumber,JobTitle,LoginID                   来自AdventureWorks2012.HumanResources.Employee                   WHERE BusinessEntityID = @BusinessEntityID';

     

SET @ParmDefinition = N'@ BusinessEntityID tinyint';

     

/ *使用第一个参数值执行字符串。 * /

     

SET @IntVariable = 197;

     

执行sp_executesql @SQLString,@ ParmDefinition,                         @BusinessEntityID = @IntVariable;

     

/ *使用第二个参数值执行相同的字符串。 * /

     

SET @IntVariable = 109;

     

执行sp_executesql @SQLString,@ ParmDefinition,                         @BusinessEntityID = @IntVariable;

对于动态,你必须传递这样的东西

  

执行sp_executesql N'Select *来自Admin WHERE ID = @ID和FirstName = @FName',N'@ ID tinyint,@ FName varchar(250)',@ ID = 2,@ FName ='admin'; < / p>