2009-03-30 20 views
30

Mam formularz, w którym użytkownicy mogą określać różne parametry, aby przeglądać niektóre dane (status, data itd.).Zapisana procedura z opcjonalnymi parametrami "WHERE"

mogę produkować kwerendy, która jest:

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

itd. Każdy WHERE jest opcjonalne (mogę zaznaczyć wszystkie wiersze z status = 3 lub wszystkie wiersze z date = 10/10/1980 lub wszystkie wiersze z status = 3 AND date = 10/10/1980 etc.).

Biorąc pod uwagę dużą liczbę parametrów, wszystkie opcjonalne, jaki jest najlepszy sposób utworzenia dynamicznej procedury przechowywanej?

Pracuję na różnych DB, takich jak: MySQL, Oracle i SQLServer.

Odpowiedz

44

Jednym z najprostszych sposobów, aby to osiągnąć:

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)) 

itp Ten całkowicie eliminuje Dynamiczny SQL i pozwala na wyszukiwanie na jednej lub kilku dziedzinach. Eliminując dynamiczny sql, usuwasz jeszcze jeden problem związany z bezpieczeństwem wstrzykiwania sql.

+2

To nie pozwala, aby wszystkie parametry były opcjonalne. W tym przykładzie @status_id musi zostać przekazany. Nawet jeśli jest pusta, musisz przekazać wartość null, aby to zostało wykonane. – Eppz

+0

Możesz podać domyślną wartość parametrów w MS SQL Server. Nie wiem o MySQL –

+4

Pamiętaj, że w zależności od Twojego RDBMS i tego, jak buforuje plany zapytań, możesz nie uzyskać najlepszej możliwej wydajności dzięki tej metodzie. –

3

można zrobić coś takiego

WHERE 
(
ParameterA == 4 OR ParameterA IS NULL 
) 

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

Utwórz procedurę tak:

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... 

To pozwoli Ci wykonać procedurę z 0 params, wszystkie params lub dowolnej # z params.

1

Jeśli chcesz uniknąć dynamicznego budowania ciągów SQL (co jest często najlepiej unikane), możesz to zrobić w przechowywanych procach, porównując każdą krytykę w swoim miejscu klauzuli z wartością domyślną, co oznacza "ignoruj". Np:

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

Jest to styl używam:

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) 

oracle

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

czytelnej i utrzymaniu sposób to zrobić (nadaje się do użycia JOIN/APPLY):

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

jednak, że to zły pomysł, w większości dużych tabel (nawet przy użyciu JOIN/Apply), ponieważ plan wykonanie nie będzie ignorować wartości NULL i generuje ogromną wydajność luki (np scaning całą tabelę w poszukiwaniu wartości NULL).

Okrężnym sposobem w SQL Server jest użycie Z (RECOMPILE) opcji w zapytaniu (dostępne od SQL 2008 SP1 CU5 (10.0.2746)).

Najlepszym sposobem na wdrożenie tego (pod względem wydajności) jest użycie bloku IF ... ELSE, po jednym dla każdej kombinacji możliwych. Może to wyczerpujące, ale będziesz miał najlepsze wyniki i nie ma znaczenia twoje ustawienia bazy danych.

Jeśli potrzebujesz więcej informacji, możesz poszukać KM. odpowiedź here.

Powiązane problemy