动态查询和datepart SQL

时间:2017-09-15 21:45:26

标签: sql-server dynamic-sql

我收到了错误

  

为dateadd指定的参数1无效。

当我尝试在SQL Server 2012中执行以下动态参数化查询时:

DECLARE @Interval nvarchar(5) = 'DAY'  
DECLARE @Increment int = 10
DECLARE @BaseDate date = getdate()
DECLARE @ResultDate date
DECLARE @Query nvarchar(2000)

SET @Query = 'SELECT @result = DATEADD(@Interval, @Increment, CAST(@BaseDate AS DATE))'    

EXECUTE sp_executesql @Query,
           N'@result date OUTPUT, @Interval varchar(50), @Increment int, @BaseDate date',
           @Interval = @Interval, @Increment = @Increment, 
           @BaseDate = @BaseDate, @result = @ResultDate OUTPUT

SELECT @ResultDate

我已将SET @Query行更改为此行。

SET @Query = 'SELECT @result = DATEADD(' + @Interval +', @Increment, CAST(@BaseDate AS DATE))'

虽然它工作正常,但我很好奇为什么第一个语句在我的动态SQL查询中导致错误? sp_executesql不生成与连接查询相同的语句吗?

2 个答案:

答案 0 :(得分:2)

因此,考虑参数化动态sql的方法是,如果它是静态SQL,则只能使用参数。 DATEADD需要特殊的日期部分关键字(例如day, hour, year等),而不是文字字符串,而不是变量。一些人遇到的问题与他们认为可以参数化类似表名的东西相同。第一个语句失败,因为即使在静态sql中,这也是无效的:

declare @increment nvarchar(5) = 'day'

select dateadd(@increment, 1, getdate())

相当于

select dateadd('day', 1, getdate())

第二个陈述成功,因为你要连接字符串" day"它被评估为关键字

答案 1 :(得分:2)

在第一种情况下,查询(@Interval扩展到其值)变为:

SELECT @result=DATEADD('DAY', @Increment, CAST(@BaseDate AS DATE))

在第二个查询中它变为:

SELECT @result=DATEADD(DAY, @Increment, CAST(@BaseDate AS DATE))

第一个查询无效,因为DATEADD的第一个参数是字符串值,编译器需要语言关键字,而SQL中的那些不一样

有关详细信息,请参阅此处:https://docs.microsoft.com/en-us/sql/t-sql/functions/dateadd-transact-sql
请注意 datepart 下的行User-defined variable equivalents are not valid。换句话说,你不能在这些"值"周围加上引号,它们不是字符串而是关键字,它们不能放在变量中。