执行sp_executesql

时间:2012-09-04 08:07:23

标签: sql sql-server

名为Emp的表包含id,name,lname,birthdate,address and salery。我想从emp中选择。 基本查询:select * from emp 如果传递lname的值,请像这样查询:select * from emp where lname = 'fgfg'。 所以我创建了以下sp。

create Procedure Proc_selectEmp
(
@name varchar(10) = null,
@lname varchar(10) = null,
@id varchar(10) = null

)
as
begin

select * from Emp
where 
(@name is null or name = @name) 
and (@lname is null or lname = @lname) 
and (@id is null or id = @id)
end

与emp一样,有13个表具有相同的列名。 所以我的tablenmae也是动态的。这就是为什么,我选择执行sp_executesql。我可以这样创建

create Procedure Proc_selectEmp
(
@name varchar(10) = null,
@lname varchar(10) = null,
@id varchar(10) = null
@tableName varchar(30)
)
as
begin
declare @query nvarchar(1000) 
set @query = @query +'select * from '+@tableName+'
where ('+@name+' is null or name = '+@name+') 
and ('+@lname+' is null or lname = '+@lname+') 
and ('+@id+' is null or id = '+@id+')
end'

execute sp_executesql @query

2 个答案:

答案 0 :(得分:1)

它会起作用,虽然非常臭,因为它要求表名是一个变量,因此表必须具有相同的列定义。

此外,不是包括@param is null or column = @param,而是完全省去不必要的过滤器,这很容易做到,因为您使用的是动态sql。这将避免parameter sniffing problem

最后,不是将列过滤器附加到字符串中,而是使用sp_executesql的参数化重载,这将保护您的SQL注入攻击,并为您处理引号的转义等。不幸的是,@ tablename无法参数化,但希望如此?这不是用户或外国提供的变量(在这种情况下,您需要更多地考虑设计和/或验证技术)。

declare @query nvarchar(max) 
set @query = N'select * from ' + @tableName + N` where (1=1)`

if (@name is not null)
  set @query = @query + N'and name = @name'

-- ... same for @id and @lname

exec sp_executesql @SQL, 
     N'@name varchar(10),
       @lname varchar(10),
       @id varchar(10)',
       @name = @name,
       @lname = @lname,
       @id = @id

修改 Re:保护un-parameterizable输入,例如动态sql中的表名或列名 - see this post here用于创意 - 使用QUOTENAME和白名单列/表名称非常突出。

答案 1 :(得分:-4)

是的,你可以,但你必须写

EXECUTE(@query)    

而不是

execute sp_executesql @query