Хранимая процедура с необязательными параметрами "WHERE" - PullRequest
37 голосов
/ 30 марта 2009

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

Я могу создать запрос:

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.

Ответы [ 6 ]

54 голосов
/ 30 марта 2009

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

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.

11 голосов
/ 30 марта 2009

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

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 параметрами, всеми параметрами или любым количеством параметров.

5 голосов
/ 08 ноября 2012

Это стиль, который я использую:

т-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)
3 голосов
/ 30 ноября 2016

Удобный и понятный способ сделать это (даже используемый с JOIN / APPLY):

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

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

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

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

Если вам нужно больше деталей, вы можете посмотреть на КМ. ответ здесь .

3 голосов
/ 30 марта 2009

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

WHERE 
(
 ParameterA == 4 OR ParameterA IS NULL
)

AND
(
 ParameterB == 12 OR ParameterB IS NULL
)
1 голос
/ 30 марта 2009

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

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...