名为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
答案 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