Sql server 使用T-SQL参数筛选表

Sql server 使用T-SQL参数筛选表,sql-server,tsql,stored-procedures,sql-injection,Sql Server,Tsql,Stored Procedures,Sql Injection,请参阅以下简单存储过程: getUsers(@name, @age, @city) etc... 如果我通过了年龄,只需过滤年龄 如果我为这两个参数传递名称和城市过滤器 我知道有一种方法可以构建我的SQL语句,然后执行MySQL 但我想做一些类似的事情: SELECT * into #tmp From Users WHERE active = 1 if(@name) SELECT * into #tmp From #tmp WHERE name = @name if(@age) S

请参阅以下简单存储过程:

getUsers(@name, @age, @city) etc...
如果我通过了年龄,只需过滤年龄 如果我为这两个参数传递名称和城市过滤器 我知道有一种方法可以构建我的SQL语句,然后执行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注入。

我相信您需要的是动态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)

在我看来,在这里使用动态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)

如果只是返回查询结果,不确定为什么需要临时表?除非您在其他地方使用它。

另一个选项是在存储过程中使用sp_ExecuteSQL来使用参数化SQL,以防止SQL注入

e、 g

在这个简单的例子中,它可能不值得,我会使用它,但如果您的查询足够复杂,它可能值得

例如,假设city在另一个表中,而记录并不总是在那里。使用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)

注意左连接。使用动态SQL,您只需在需要时动态添加一个内部联接,在某些情况下,这将产生更好的性能

澄清一下,您在T-SQLPHP、C.Net、VB.Net、Java等方面使用的是什么服务器端处理语言?这真的必须在存储过程中完成吗@AR的答案是正确的,可以工作,但是如果在发送到数据库之前能够在应用程序中构建查询,则可以获得更高效的查询,而且这可以在没有SQL注入风险的情况下完成。这里有很多关于类似主题的问题,所以根据您的应用,应该有适合的答案。我正在使用C来执行当前的存储过程。。。但我将要做的是使用本文中建议的动态SQL参数,并用C构建我的查询。这就是我目前所拥有的,并试图摆脱。。。这可能会导致系统SQl注入漏洞,而这正是我试图更改的方式。如果您验证用户输入,则不会出现此漏洞,我的意思是if@name=@someValidUserInput。只有在已知值有效的情况下,用户提供的字符串才会包含在查询中。如果您查找name=Jaider,则将提供@name='Jaiders',否则将不起作用。。。但是我所寻找的解决方案,只需要通过@name='Jaiders',Actve=1不应该独立于remaing子句吗?例如,如果年龄=@age,此查询将返回活动为1的结果。这已经被接受为一个答案,但在我看来where子句应该是'where Active=1和@age为NULL或age=@age和@Name为NULL或Name=@Name和@City为NULL或City=@City。我想你是对的,但我的逻辑只是基于他在问题中的内容。当然,它可以根据实际需要进行调整如果我传递的名字和城市不同时过滤。。。另外,因为所有连接都带有OR,当任何其他筛选器为true且处于非活动状态时,它们会给我带来非活动记录。这更接近我要查找的内容:从active=1且@age为null或age=@age且@name为null或name=@name且@city为null或city=@city的用户中选择*-进入tmp
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)