我正在尝试运行此SQL语法,但我一直收到错误:
Msg 137,Level 15,State 2,Line 1
必须声明标量变量" @ startDate"。
但是,在我看来,变量已经在我的程序开始时声明了。为什么会抛出错误,我需要做些什么才能解决它?
我使用这种语法来调用我的存储过程:
exec [dbo].[DoThis] '01/01/2015','01/31/2015'
这是完整的程序,它会出现上面的编译错误。
ALTER Procedure [dbo].[DoThis]
(
@startDate datetime,
@endDate datetime
)
As
Declare @storename varchar(500), @dblocation varchar(500), @sql varchar(max)
Select storename, dblocation
INTO #allstores
FROM tbl_allstores
where sales >= '1,000,000'
Declare c1 Cursor For
Select storename, dblocation
FROM #allstores
Open c1
Fetch Next From c1 Into @storename, @dblocation
While @@FETCH_STATUS = 0
Begin
Set @sql = 'Insert Into #storeinfo (storename, employeename, employeeaddress, employeephone) '
+'Select '''+@storename+''' As ''storename'', '
+'employeename, employeeaddress, employeephone '
+'From '+@dblocation+' '
+'where employeestatus = ''Active'' '
+'and CAST(hiredate As Date) BETWEEN CAST(@startDate As Date) AND CAST(@endDate As Date) '
Print(@sql)
exec(@sql)
Fetch Next From c1 Into @storename, @dblocation
End
Close c1
Deallocate c1
Select * from #storeinfo
Drop Table #allstores
Drop Table #storeinfo
答案 0 :(得分:7)
当你exec(@sql)
创建一个带有自己的局部变量的新上下文时,你还没有将@startDate
值传递到该上下文中。
相反,请为您的SQL字符串声明参数:
exec sp_executesql @sql, '@startDate datetime, @endDate datetime',
@startDate, @endDate;
这些名称现在可供您的SQL使用,参数将传递给它们。
这种方法更好,因为它将变量视为参数更安全,因为它降低了SQL注入的风险。
作为附加提示,您还应该将@storeName作为参数传递。据我所知,你不能将@dbname作为参数传递,所以你应该确保它被正确引用。
所以完整的事情将是:
Set @sql = 'Insert Into #storeinfo (storename, employeename, employeeaddress, employeephone) '
+' Select @storename As ''storename'', '
+' employeename, employeeaddress, employeephone '
+' From '+QUOTENAME(@dblocation)+' '
+' where employeestatus = ''Active'' '
+' and CAST(hiredate As Date) '
+' BETWEEN CAST(@startDate As Date) AND CAST(@endDate As Date) '
Print(@sql)
exec sp_executesql @sql,
'@startDate datetime, @endDate datetime, @storeName nvarchar(100)',
@startDate, @endDate, @storeName;
答案 1 :(得分:3)
更改为:
+'and CAST(hiredate As Date) BETWEEN CAST(''' + @startDate + ''' As Date) AND CAST(''' + @endDate + ''' As Date) '
我认为会起作用,或者至少接近。您的问题是@startDate
,@endDate
实际上并未在执行动态SQL的单独范围内声明。
基本上exec(@sql)
是与存储过程范围的单独范围,实际上是声明@startDate
和@endDate
。