将参数传递给declated变量T-SQL

时间:2015-02-23 01:00:20

标签: sql-server tsql

我在存储过程中有一个小版本的问题,我想将参数传递给如下:

  create procedure VariableTest
  @Date1 DATETIME,
  @Date2 DATETIME,
  @CustomName1 NVARCHAR(100),
  @CustomNum2 INT
AS

 DECLARE @Condition NVARCHAR(MAX)
 DECLARE @SQL NVARCHAR(MAX)

 IF(LEN(@CustomName1) > 0)
    SET @Condition = 'CustomerName = ' + @CustomName1;

 IF(LEN(@CustomNum2) > 0 AND @CustomNum2 > 0)
    SET @Condition = 'ClientNumber = ' + @CustomNum2;

 SET @SQL =
  'SELECT * FROM MyExampleTable ex
   WHERE DateEx1 between ' + @Date1 + ' AND ' + @Date2 + '
   AND ' + @Condition + '
   ORDER BY ex.Sort'

exec @SQL

我遇到的问题是,当我打印sql时,日期没有引用它们并且它们是日期时间格式,另一个问题是在CustomerName可用的条件下客户名称它们周围也没有引号......

我怎样才能使它在sql字符串中我可以在传递的参数周围包含那些引号?

OPTED SOLUTION:

  create procedure VariableTest
  @Date1 DATETIME,
  @Date2 DATETIME,
  @CustomName1 NVARCHAR(100),
  @CustomNum2 INT
AS

 DECLARE @Condition NVARCHAR(MAX)
 DECLARE @SQL NVARCHAR(MAX)

 IF(LEN(@CustomName1) > 0)
    SET @Condition = 'CustomerName = @MyVal1';

 IF(LEN(@CustomNum2) > 0 AND @CustomNum2 > 0)
    SET @Condition = 'ClientNumber = @MyVal2';

 DECLARE @MyParams NVARCHAR(200)
 SET @MyParams = N'@date1 datetime, @date2 datetime, @MyVal1 NVARCHAR(200), @MyVal2 int';

 SET @SQL =
  'SELECT * FROM MyExampleTable ex
   WHERE DateEx1 between @date1  AND @date2
   AND ' + @Condition + '
   ORDER BY ex.Sort'

EXECUTE exec sp_executesql 
    @SQL,
    @MyParams,
    @date1 = @Date1,
    @date2 = @Date2,
    @MyVal1 = @CustomName1,
    @MyVal2 = @CustomNum2;

4 个答案:

答案 0 :(得分:2)

你的程序很容易使用sql-injection避免连接参数并使用像这样的参数化查询....

  CREATE PROCEDURE VariableTest
  @Date1 DATETIME,
  @Date2 DATETIME,
  @CustomName1 NVARCHAR(100),
  @CustomNum2 INT
AS
BEGIN 
  SET NOCOUNT ON;

 DECLARE @SQL NVARCHAR(MAX);

 SET @SQL = N'SELECT * FROM MyExampleTable  '
          + N' WHERE DateEx1 between  @Date1 AND @Date2 '
          + CASE WHEN LEN(@CustomName1) > 0 
             THEN N' AND CustomerName = @CustomName1 ' ELSE N'' END
          + CASE WHEN LEN(@CustomNum2) > 0 AND @CustomNum2 > 0
             THEN N' AND ClientNumber =  @CustomNum2 ' ELSE N'' END
          + N' ORDER BY [Sort] '

  exec sp_executesql @SQL
                    ,N'@Date1 DATETIME, @Date2 DATETIME
                      @CustomName1 NVARCHAR(100), @CustomNum2 INT '
                    ,@Date1
                    ,@Date2
                    ,@CustomName1
                    ,@CustomNum2

END

答案 1 :(得分:1)

您可以在没有动态查询的情况下执行此操作

SELECT * FROM MyExampleTable ex
WHERE DateEx1 between  @Date1  AND  @Date2 
AND ((LEN(@CustomName1) > 0 AND CustomerName = @CustomName1) 
or (LEN(@CustomNum2) > 0 AND @CustomNum2 > 0 and ClientNumber =  @CustomNum2))
ORDER BY ex.Sort

考虑到如果满足where子句,则应在IF子句中应用这两个条件

动态查询。

您需要添加更多引号才能获得date

周围的引号
  IF( Len(@CustomName1) > 0 )
  SET @Condition = 'CustomerName = ''' + @CustomName1 + '';

IF( Len(@CustomNum2) > 0
    AND @CustomNum2 > 0 )
  SET @Condition = 'ClientNumber = '
                   + CONVERT(VARCHAR(50), @CustomNum2);

SET @SQL = 'SELECT * FROM MyExampleTable ex
   WHERE DateEx1 between '''
           + CONVERT(VARCHAR(50), @Date1) + ''' AND '''
           + CONVERT(VARCHAR(50), @Date2) + '''
   AND '
           + @Condition + '
   ORDER BY ex.Sort'

exec(@SQL) 

答案 2 :(得分:0)

Jeroen发布的链接是使用动态SQL的绝佳资源,非常值得阅读(特别是为了避免上述注入攻击)。

那就是说,你想在这里使用的是系统存储过程sp_executesql。我们的想法是你可以传入(和传出)变量,这样你就不必在不需要时将它们连接起来。快速脏的解释是你声明一个额外的变量来保存你想要传入的参数的声明,然后你执行sp_executesql指示sql文本(第一个参数),哪个变量保存你的参数声明(第二个参数)和多个变量如你声明了(第3到第n个参数)。这是关于sp_executesql的MSDN文档:

https://msdn.microsoft.com/en-us/library/ms188001.aspx

然后,您的代码将会是这样的:

  create procedure VariableTest
  @Date1 DATETIME,
  @Date2 DATETIME,
  @CustomName1 NVARCHAR(100),
  @CustomNum2 INT
AS

 DECLARE @Condition NVARCHAR(MAX)
 DECLARE @SQL NVARCHAR(MAX)
 declare @parameters nvarchar(2000)

 IF(LEN(@CustomName1) > 0)
    SET @Condition = 'CustomerName = ' + @CustomName1;

 IF(LEN(@CustomNum2) > 0 AND @CustomNum2 > 0)
    SET @Condition = 'ClientNumber = ' + @CustomNum2;

 SET @SQL =
  'SELECT * FROM MyExampleTable ex
   WHERE DateEx1 between @Date1 AND @Date2
   AND ' + @Condition + '
   ORDER BY ex.Sort'

set @parameters = '@date1 datetime, @date2 datetime'
exec sp_executesql 
    @sql,
    @params,
    @date1,
    @date2

答案 3 :(得分:0)

我并不特别喜欢您选择的解决方案。

NoDisplayName通过不使用动态查询使其正确。使用动态查询意味着您无法获得SP查询计划缓存的好处。

如果您使用查询错误创建SP,则非动态查询还会产生额外的好处,因为它会生成编译问题。动态SQL隐藏了所有这些。

如果您正在使用LIKE语句,那么您唯一会遇到性能问题。值"%ABC"," AB%C"和" ABC%"都使用不同的查询计划。使用equals时,您可以安全地缓存查询计划。

这就是我使用的: SELECT * FROM MyExampleTable ex WHERE DateEx1 between @Date1 AND @Date2 AND ((LEN(@CustomName1) > 0 AND CustomerName = @CustomName1) OR (@CustomNum2 > 0 and ClientNumber = @CustomNum2)) ORDER BY ex.Sort 如果参数不包含任何内容,我也会将参数传递给NULL。