2009-03-30 22 views
30

Ich habe ein Formular, wo Benutzer verschiedene Parameter angeben können, um durch einige Daten (Status, Datum usw.) zu graben.Gespeicherte Prozedur mit optionalen "WHERE" -Parametern

Ich kann eine Abfrage erzeugen, ist:

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

usw. Jeder WHERE optional ist (ich alle Zeilen mit status = 3 auswählen können, oder alle Zeilen mit date = 10/10/1980, oder alle Zeilen mit status = 3 AND date = 10/10/1980 usw.).

Angesichts einer großen Anzahl von Parametern, alle optional, was ist der beste Weg, um eine dynamische gespeicherte Prozedur zu machen?

Ich arbeite an verschiedenen DB, wie: MySQL, Oracle und SQLServer.

Antwort

44

Eine der einfachsten Möglichkeiten, um dies zu erreichen:

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

usw. Dies eliminiert vollständig dynamische SQL und ermöglicht es Ihnen, auf einem oder mehreren Feldern zu suchen. Durch das Eliminieren von dynamic sql entfernen Sie ein weiteres Sicherheitsrisiko bezüglich der SQL-Injektion.

+2

Dies ermöglicht nicht, dass alle Parameter optional sind. In diesem Beispiel muss @status_id übergeben werden. Selbst wenn es null ist, müssen Sie null übergeben, damit dies ausgeführt wird. – Eppz

+0

Sie können einen Standardwert für Parameter in MS SQL Server angeben. Ich weiß nichts über MySQL –

+4

Denken Sie daran, dass Sie mit dieser Methode möglicherweise nicht die bestmögliche Leistung erzielen, je nach RDBMS und Caching von Abfrageplänen. –

3

Sie können so etwas wie

WHERE 
(
ParameterA == 4 OR ParameterA IS NULL 
) 

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

Erstellen Sie Ihre Prozedur tun:

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

Dies ermöglicht es Ihnen, das Verfahren mit 0 params, alle params oder einer beliebigen Anzahl der params auszuführen.

1

Wenn Sie vermeiden möchten, dass SQL-Strings dynamisch erstellt werden (was oft vermieden wird), können Sie dies in gespeicherten Prozeduren tun, indem Sie jeden Wert in Ihrer where mit einem Standardwert vergleichen, der "ignore" entspricht. ZB:

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

Dies ist der Stil, den ich verwenden:

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) 

Orakel

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

A lesbar und wartbar Weg, es zu tun (sogar verwendbar mit JOIN/APPLY):

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

aber es auf den meisten großen Tischen eine schlechte Idee (noch mit JOIN/apply), da Ihr Ausführungsplan nicht NULL-Werte ignoriert und erzeugt massive Performance-Lücke (ex: scaning alle eine Tabelle für NULL-Werte gesucht).

Ein Umweg in SQL Server ist die Verwendung von WITH (RECOMPILE) -Optionen in Ihrer Abfrage (verfügbar seit SQL 2008 SP1 CU5 (10.0.2746)).

Der beste Weg, dies zu erreichen (performance weise), ist die Verwendung von IF ... ELSE Block, einer für jede mögliche Kombination. Vielleicht ist es anstrengend, aber Sie werden die besten Leistungen haben und es ist egal, welche Datenbankeinstellungen Sie haben.

Wenn Sie weitere Informationen benötigen, können Sie nach KM suchen. Antwort here.

Verwandte Themen