使用sp_executesql运行带变量的xp_cmdshell

时间:2014-04-01 05:31:52

标签: sql sql-server-2008-r2

尝试使用sp_executesql运行xp_cmdshell但没有成功,数据库是SQL Server 2008R2

这是SQL

DECLARE @sql nvarchar(max) = N'EXEC xp_cmdshell ''BCP "SELECT data FROM TableA WHERE id = @id" queryout C:\Temp\test.dat -T -N'''
EXEC sp_executesql @sql, N'@id numeric(19, 0)', @id = 1234

错误是

Error = [Microsoft][SQL Server Native Client 10.0][SQL Server]Must declare the scalar variable "@id".

请帮助,谢谢!

2 个答案:

答案 0 :(得分:2)

问题是变量@id不存在于过程xp_cmdshell的范围内。 换句话说,@ if不会被字符串SELECT data FROM TableA WHERE id = @id中的实际值替换。最好替换名为@id的变量,然后执行查询。

SET @sql = REPLACE(@sql,'@id',@id);

您的代码已更新:

DECLARE @id NUMERIC(19, 0)
SET @id = 3087

DECLARE @sql nvarchar(max) = N'EXEC xp_cmdshell ''BCP "SELECT data FROM TableA WHERE id = @id" queryout "C:\Temp\test.dat" -T -N '''
SET @sql = REPLACE(@sql,'@id',@id);
EXEC sp_executesql @sql

答案 1 :(得分:1)

错误是由于@sql字符串中的@id变量引用位于转义子字符串中(即由xp_cmdshell执行的BCP字符串)。所以你可以逃脱该子字符串。

DECLARE @id NUMERIC(19, 0)
DECLARE @sql NVARCHAR(MAX)

SET @id = 1234
SET @SQL = N'DECLARE @BCP NVARCHAR(4000); 
SET @BCP = ''BCP "SELECT data FROM TableA WHERE id = ''
           + CONVERT(NVARCHAR(30), @id) + N''" queryout C:\Temp\test.dat -T -N'';
PRINT @BCP
EXEC xp_cmdshell @BCP;
'

EXEC sp_executesql @sql, N'@id NUMERIC(19, 0)', @id = 1234

但这仍然比这里需要更多的努力。只需将@id值连接到字符串中,然后使用EXEC()。不需要使用sp_executesql,因为您不需要缓存查询计划的性能优势。

DECLARE @id NUMERIC(19, 0)
DECLARE @sql NVARCHAR(MAX)
SET @id = 1234
SET @SQL = N'EXEC xp_cmdshell ''BCP "SELECT data FROM TableA WHERE id = '  
           + CONVERT(NVARCHAR(30), @id) + N'" queryout C:\Temp\test.dat -T -N'''

PRINT @SQL
EXEC(@SQL)