2008-11-25 14 views
14

Ich erstelle eine gespeicherte Prozedur, um Suchergebnisse zurückzugeben, wenn einige der Parameter optional sind.SQL if-Anweisung in where-Klausel zum Durchsuchen der Datenbank

Ich möchte eine "if-Anweisung" in meinem wo Klausel, aber kann es nicht funktionieren. Die , wobei-Klausel nur durch die Nicht-Null-Parameter filtern sollte.

Hier ist die sp

ALTER PROCEDURE spVillaGet 
-- Add the parameters for the stored procedure here 
@accomodationFK int = null, 
@regionFK int = null, 
@arrivalDate datetime, 
@numberOfNights int, 
@sleeps int = null, 
@priceFloor money = null, 
@priceCeil money = null 
AS 
BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

-- Insert statements for procedure here 
select tblVillas.*, tblWeeklyPrices.price from tblVillas 
INNER JOIN tblWeeklyPrices on tblVillas.villaId = tblWeeklyPrices.villaFK 
where 
    If @accomodationFK <> null then 
     accomodationTypeFK = @accomodationFK 
    @regionFK <> null Then 
     And regionFK = @regionFK 
    IF @sleeps <> null Then 
     And sleeps = @sleeps 
    IF @priceFloor <> null Then 
     And price >= @priceFloor And price <= @priceCeil 


END 

Irgendwelche Ideen, wie dies zu tun?

Antwort

25
select tblVillas.*, tblWeeklyPrices.price 
from tblVillas 
INNER JOIN tblWeeklyPrices on tblVillas.villaId = tblWeeklyPrices.villaFK 
where (@accomodationFK IS null OR accomodationTypeFK = @accomodationFK) 
    AND (@regionFK IS null or regionFK = @regionFK) 
    AND (@sleeps IS null OR sleeps = @sleeps) 
    AND (@priceFloor IS null OR (price BETWEEN @priceFloor And @priceCeil)) 
+0

danke für Ihre Hilfe, aber der Wert in der Datenbank ist nicht null. Ich möchte diesen Teil der where-Klausel überspringen, wenn null für einen der Parameter übergeben wird. – mancmanomyst

+4

Warum das funktioniert: Wenn @var null ist, dann ist die ganze Zeile wahr, unabhängig vom Rest der Zeile (also ignoriert und ungefiltert). Wenn es nicht null ist, dann ist die Zeile falsch *, es sei denn * ColVar = @ var, wodurch der Filter angewendet wird. Ich war verwirrt, als ich das erste Mal diesen Filterstil gelesen habe, aber jetzt überall benutze. –

+0

mancmanomyst.myopenid.com: das ist, was das tut. Ich schlage vor, eine Wahrheitstabelle zu erstellen - sie ist zunächst nicht intuitiv. –

0

Sie können auch IsNull verwenden oder

Where accomodationTypeFK = IsNull(@accomodationFK, accomodationTypeFK) 
    And regionFK = Coalesce(@regionFK,regionFK) 
    And sleeps = IsNull(@sleeps,sleeps) 
    And price Between IsNull(@priceFloor, Price) And IsNull(priceCeil, Price) 

Dies tut Vorschlag das gleiche wie Michaels oben ...

IsNull() und Coalesce() arbeiten mehr Coalesce Funktion oder weniger Auf die gleiche Weise geben sie das erste Nicht-Null-Argument in der Liste zurück, außer iSNull erlaubt nur 2 Argumente und Coalesce kann eine beliebige Zahl annehmen ...

http://blogs.msdn.com/sqltips/archive/2008/06/26/differences-between-isnull-and-coalesce.aspx

+0

Macht dies den Optimierer kaputt oder ist es schlau genug, dies gut zu machen? Ich werde nervös, wenn ich solche Vergleiche sehe. Gute Erwähnung, obwohl. Ich benutze diese Funktionen sehr. Eine andere weniger bekannte Funktion ist NULLIF (a, b), die null zurückgibt, wenn a und b gleich sind. –

+0

Nicht sicher über Optimierer .. verlassen sich auf die Tatsache, dass die Spalte ist allein auf der einen Seite der = Operator, so sollte es SARG-fähig sein. Und NullIf() ist auch kewl, aber ich finde nicht so viel Gelegenheit, es zu verwenden ... –

+0

Dito: Beachten Sie, dass obwohl diese Technik häufig verwendet wird, es Fallstricke haben kann, besonders wenn es eine große Anzahl von optionalen gibt Parameter. Führen Sie eine SO-Suche nach "Parameter-Sniffing" und "zwischengespeicherten Abfrageplänen" durch. –

0

Wir haben eine Menge von COALESCE hier in der Vergangenheit für "dynamic WHERE clauses" verwendet, wie Sie sprechen.

SELECT * 
FROM vehicles 
WHERE ([vin] LIKE COALESCE(@vin, [vin])  + '%' ESCAPE '\') 
    AND ([year] LIKE COALESCE(@year, [year]) + '%' ESCAPE '\') 
    AND ([make] LIKE COALESCE(@make, [make]) + '%' ESCAPE '\') 
    AND ([model] LIKE COALESCE(@model, [model]) + '%' ESCAPE '\') 

Ein großes Problem stellt sich allerdings, wenn Sie Filter für eine Spalte optional mögen, die auch NULL sein kann ..., wenn die Daten in der Spalte null für eine bestimmte Zeile und der Benutzer nichts eingeben suchen für diese Spalte (so die Benutzereingabe ist auch null), dann wird die Zeile nicht einmal in den Ergebnissen angezeigt (was, wenn Ihre Filter optional sind, ist inkorrekt ausschließenden Verhalten).

Damit NULL festlegbare Felder zu kompensieren, erhalten Sie wie so unordentliche aussehendes SQL zu tun mit bis:

SELECT * 
FROM vehicles 
WHERE (([vin] LIKE COALESCE(@vin, [vin])  + '%' ESCAPE '\') 
     OR (@vin IS NULL AND [vin] IS NULL)) 
    AND (([year] LIKE COALESCE(@year, [year]) + '%' ESCAPE '\') 
     OR (@year IS NULL AND [year] IS NULL)) 
    AND (([make] LIKE COALESCE(@make, [make]) + '%' ESCAPE '\') 
     OR (@make IS NULL AND [make] IS NULL)) 
    AND (([model] LIKE COALESCE(@model, [model]) + '%' ESCAPE '\') 
     OR (@model IS NULL AND [model] IS NULL)) 
+0

Wie ich mich erinnere, ist dies ein weiterer Unterschied zwischen IsNull und Coalesce ... Einer von ihnen (ich vergesse was) zeigt dieses Verhalten, und der andere nicht. –

+0

Jetzt muss ich nachsehen ... –

+0

IsNull funktioniert hier ok. Coalesce zeigt dieses Problem. Aber Sie können es auch mit einem Cast lösen ... http://blogs.msdn.com/sqltips/archive/2008/06/26/differences-between-isnull-and-coalesce.aspx –

0

Nur damit Sie verstehen, IF prozeduralen Code in T-SQL ist. Es kann nicht in einer insert/update/delete/select-Anweisung verwendet werden, es kann nur verwendet werden, um zu bestimmen, welche von zwei Anweisungen ausgeführt werden soll. Wenn Sie innerhalb einer Anweisung verschiedene Möglichkeiten benötigen, können Sie wie oben beschrieben vorgehen oder eine CASE-Anweisung verwenden.

-2

Versuchen Sie, Ihre IF-Anweisung um die gesamte SQL-Anweisung zu setzen. Das bedeutet, dass für jede Bedingung eine SQL-Anweisung vorhanden ist. Das hat für mich funktioniert.

+1

dies könnte zu einem führen verdammt viel Code. – Duncan

+0

stimmte mit Duncan überein. Versuchen, das in einer gespeicherten Prozedur zu tun, die 6 Params akzeptiert. – Gagan