请参阅此简单存储过程:
getUsers(@name, @age, @city) etc...
我知道有一种方法可以构建我的SQL语句然后EXEC(mySQL)
但我想做点什么:
SELECT * into #tmp From Users WHERE active = 1
if(@name)
SELECT * into #tmp From #tmp WHERE name = @name
if(@age)
SELECT * into #tmp From #tmp WHERE age = @age
if(@city)
SELECT * into #tmp From #tmp WHERE city = @city
SELECT * From #tmp -- result
这样我们可以避免SQL注入。
答案 0 :(得分:4)
在我这里使用动态SQL似乎会让你更容易受到注入攻击。尝试:
select *
-- into #tmp
from Users
where active = 1
or (@age is not null and age = @age)
or (@name is not null and name = @name)
or (@city is not null and city = @city)
如果您只是返回查询结果,不确定为什么需要临时表?除非你在其他地方使用它。
答案 1 :(得分:0)
另一种选择是在存储过程中使用sp_ExecuteSQL来使用参数化SQL,以保护您免受SQL注入
e.g。
DECLARE @SQL Nvarchar(max)
SET @SQL ='select *
from Users
where active = 1'
IF @Name is not null
SET @SQL = @SQL + ' AND name = @Name'
IF @Age is not null
SET @SQL = @SQL + ' AND age = @Age'
IF @City is not null
SET @SQL = @SQL + ' AND city = @City'
exec sp_executeSQL @SQL, N'@Age int,
@Name varchar(255), @City varchar(255)',
@Age,
@Name,
@City
在这个简单的情况下,它可能不值得,我会使用technique described by AR,但如果你的查询足够复杂,那么它可能是值得的。
例如,假设城市在另一个表中并且记录并不总是存在。使用AR的技术,您需要这样做
select *
-- into #tmp
from Users
LEFT JOIN user_city
ON user.user_Id = user_city.user_Id
and @City is not null --We only want the join when @City is passed in
where active = 1
or (@age is not null and age = @age)
or (@name is not null and name = @name)
or (@city is not null and city = @city)
请注意LEFT JOIN
。使用动态SQL,您只需在需要时动态添加INNER JOIN
,在某些情况下可以产生更好的性能。
答案 2 :(得分:-1)
我相信你所寻找的是动态SQL。我们的想法是构建一个查询字符串,然后使用EXEC(或sp_executesql)将字符串作为SQL语句运行。
所以给你一个想法,比如:
set @sql = 'select * into #tmp1 From #tmp2 '
if @name = @someValidUserInput
begin
set @sql = @sql + ' where name = @name'
...
end
exec(@sql)