Использование параметров T-SQL для фильтрации таблицы - PullRequest
2 голосов
/ 07 марта 2012

См. Эту простую хранимую процедуру:

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.

Ответы [ 3 ]

4 голосов
/ 07 марта 2012

Мне кажется, использование здесь динамического 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)

Не знаете, зачем вам временная таблица, если вы только что возвращаете результаты запроса?Если вы не используете его в другом месте.

0 голосов
/ 07 марта 2012

Другим вариантом является использование параметризованного SQL с использованием sp_ExecuteSQL в хранимой процедуре, которая защищает вас от SQL-инъекций

например,

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

В этом простом случае это, вероятно, не стоит, и я быиспользуйте технику , описанную 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, когда вам это нужно, что в некоторых случаях даст лучшую производительность.

0 голосов
/ 07 марта 2012

Я считаю, что вы ищете динамический 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)
...