2009-03-30 4 views
30

У меня есть форма, в которой пользователи могут указывать различные параметры для обработки некоторых данных (статус, дата и т. Д.).Сохраненная процедура с опциональными параметрами «WHERE»

я могу производить запрос, который является:

SELECT * FROM table WHERE: 
status_id = 3 
date = <some date> 
other_parameter = <value> 

и т.д. Каждый WHERE не является обязательным (я могу выбрать все строки с status = 3, или все строки с date = 10/10/1980, или все строки с status = 3 AND date = 10/10/1980 т.д.).

Учитывая большое количество параметров, все необязательные, что является лучшим способом для создания динамической хранимой процедуры?

Я работаю над различными БД, такими как: MySQL, Oracle и SQLServer.

ответ

44

Один из самых простых способов сделать это:

SELECT * FROM table 
WHERE ((@status_id is null) or (status_id = @status_id)) 
and ((@date is null) or ([date] = @date)) 
and ((@other_parameter is null) or (other_parameter = @other_parameter)) 

и т.д. Это полностью исключает динамический SQL и позволяет осуществлять поиск по одному или нескольким полям. Исключая динамический sql, вы удаляете еще одну проблему безопасности в отношении SQL-инъекции.

+2

Это не означает, что все параметры являются необязательными. В этом примере необходимо передать @status_id. Даже если это значение null, вам нужно передать значение null для этого. – Eppz

+0

Вы можете указать значение по умолчанию для параметров в MS SQL Server. Я не знаю о MySQL –

+4

Просто имейте в виду, что в зависимости от вашей РСУБД и того, как она кэширует планы запросов, вы можете не получить наилучшую производительность с помощью этого метода. –

3

Вы можете сделать что-то вроде

WHERE 
(
ParameterA == 4 OR ParameterA IS NULL 
) 

AND 
(
ParameterB == 12 OR ParameterB IS NULL 
) 
11

Создайте свою процедуру, как это:

CREATE PROCEDURE [dbo].[spXXX] 
    @fromDate datetime = null, 
    @toDate datetime = null, 
    @subCode int = null 
as 
begin 
set NOCOUNT ON 
/* NOCOUNT limits the server feedback on select results record count */ 
SELECT 
    fields... 
FROM 
    source 
WHERE 
    1=1 
--Dynamic where clause for various parameters which may or may not be passed in. 
and (@fromDate is null or [dateField] >= @fromDate) 
and (@toDate is null or [dateField] <= @toDate) 
and (@subCode is null or subCode= @leaveTypeSubCode) 
order by fields... 

Это позволит выполнить процедуру с 0 Params, все Params или любого # из Params.

1

Если вы хотите избежать динамического создания SQL-строк (что часто бывает лучше всего избежать), вы можете сделать это в хранимых процедурах, сравнив каждый критерий в своем месте, где указано значение по умолчанию, которое равнозначно «игнорировать». Например:

select * from Table where 
    (@Col1 IS NULL OR Col1 = @Col1) /*If you don't want to filter in @col, pass in NULL*/ 
    AND 
    (@Col2 IS NULL OR Col2 = @Col2) 
4

Это стиль я использую:

T-SQL

SELECT *   
FROM table   
WHERE  
status_id = isnull(@status_id ,status_id)  
and date = isnull(@date ,date)  
and other_parameter = isnull(@other_parameter,other_parameter) 

оракул

SELECT *   
FROM table   
WHERE  
status_id = nval(p_status_id ,status_id)  
and date = nval(p_date ,date)  
and other_parameter = nval(p_other_parameter,other_parameter) 
2

Считываемый и ремонтопригодны способ сделать это (даже применимый с JOIN/APPLY):

where 
     (@parameter1 IS NULL OR your_condition1) 
    and (@parameter2 IS NULL OR your_condition2) 
-- etc 

Однако это плохая идея на большинстве больших таблиц (даже больше, используя JOIN/ОТНОСИТЬСЯ), так как ваш план выполнения не будет игнорировать NULL значения и формирует массивную лазейку производительности (например: просмотрит все таблицы поиска для значений NULL).

Обходной путь в SQL Server заключается в использовании опций WITH (RECOMPILE) в вашем запросе (доступно с SQL Server 2008 SP1 CU5 (10.0.2746)).

Наилучший способ реализовать это (разумный результат) - использовать блок IF ... ELSE, по одному для каждой комбинации. Возможно, это изнурительно, но у вас будут лучшие результаты, и это не имеет значения для настроек вашей базы данных.

Если вам нужна дополнительная информация, вы можете найти KM. ответ here.

Смежные вопросы