Wie man bedingt Filter auf eine Spalte in einer WHERE-Klausel?

stimmen
12

OK, die x-te bedingte Spalte Frage:

Ich schreibe eine gespeicherte Prozedur, die einen Eingabeparameter, die auf einem von mehreren Flag Spalten zugeordnet sind. Was ist der beste Weg, auf die gewünschte Spalte zu filtern? Ich bin zur Zeit auf SQL2000, sondern um zu SQL2008 zu bewegen, so dass ich eine zeitgemäße Lösung, wenn man die zur Verfügung zu nehmen.

Die Tabelle im sproc abgefragt aussieht

ID ...  fooFlag  barFlag  bazFlag  quuxFlag
--      -------  -------  -------  --------
01         1        0       0          1
02         0        1       0          0
03         0        0       1          1
04         1        0       0          0

und ich will etwas tun, wie

select ID, name, description, ...
from myTable
where (colname like @flag + 'Flag') = 1

so , wenn ich die sproc nennen wie exec uspMyProc @flag = 'foo'würde ich wieder die Zeilen 1 und 4 erhalten.

Ich weiß, ich kann nicht das Teil in Pars direkt in SQL tun. Um dynamische SQL zu tun, ich werde die gesamte Abfrage in einen String stopfen müssen, verketten die @flag param in der WHERE-Klausel und dann die Zeichenfolge exec. Abgesehen von dem schmutzigen Gefühl, das ich bekommen, wenn dynamische SQL tun, meine Frage ist ziemlich groß (ich bin ein paar Dutzend Felder auswählen, Füge- 5 Tische, ein paar Funktionen aufrufen), so ist es eine große Riese String alles wegen einer einzigen Zeile in einem 3-Zeilen-WHERE-Filter.

Alternativ könnte ich 4 Kopien der Abfrage haben und unter ihnen in einer CASE-Anweisung auswählen. Dies läßt den SQL-Code direkt ausführbaren Datei (und vorbehaltlich der Syntax hilighting, etc.), aber auf Kosten der großen Teile des Codes zu wiederholen, da ich nicht den Fall auf nur die WHERE-Klausel verwenden kann.

Gibt es noch andere Optionen? Jede tricky beitritt oder logische Operationen, die angewendet werden können? Oder sollte ich einfach darüber hinwegkommen und die dynamischen SQL-exec?

Veröffentlicht am 30/12/2009 um 03:57
quelle vom benutzer
In anderen Sprachen...                            


6 antworten

stimmen
19

Es gibt ein paar Möglichkeiten, dies zu tun:

Sie können mit einer Case-Anweisung dies zu tun.

select ID, name, description, ...
from myTable
where CASE
    WHEN @flag = 'foo' then fooFlag
    WHEN @flag = 'bar' then barFlag
END = 1

Sie können IF verwenden.

IF (@flag = 'foo') BEGIN
    select ID, name, description, ...
    from myTable
    where fooFlag = 1
END ELSE IF (@flag = 'bar') BEGIN
    select ID, name, description, ...
    from myTable
    where barFlag = 1
END

....

Sie können eine where-Klausel mit vielen Klammern kompliziert haben.

select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1)
OR (@flag = 'bar' and barFlag = 1) OR ...

Sie können dies mit dynamischer SQL:

DECLARE @SQL nvarchar(4000)

SELECT @SQL = N'select ID, name, description, ...
from myTable
where (colname like ''' + @flag + 'Flag'') = 1'

EXECUTE sp_ExecuteSQL @SQL, N''

Es gibt mehr, aber ich denke, eine davon wird erhalten Sie gehen.

Beantwortet am 30/12/2009 um 04:02
quelle vom benutzer

stimmen
4

„Alternativ könnte ich 4 Kopien der Abfrage haben und unter ihnen in einer CASE-Anweisung auswählen.“

Sie brauchen nicht Ihre gesamte Abfrage 4 mal zu kopieren, fügen Sie einfach alle Möglichkeiten in die where-Klauseln in Ihrer einzigen Kopie der Abfrage:

select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1) OR (@flag = 'bar' and barFlag = 1) OR ...
Beantwortet am 30/12/2009 um 04:03
quelle vom benutzer

stimmen
0

Sie könnten einen Parameter für jede mögliche Flag-Spalte, dann prüfen, ob der Parameter null ist oder der Wert in der Spalte auf den Parameter gleich. Dann kommt man in einem 1 für die Flags, die Sie die anderen null überprüfen und verlassen wollen.

select id, name, description, ...
from myTable
where (@fooFlag is null or fooFlag = @fooFlag) AND
      (@barFlag is null or barFlag = @barFlag) AND
      ...

Ehrlich gesagt, obwohl, scheint dies ein idealer Kandidat für eine dynamische LINQ-Abfrage zu bauen und Überspringen der SPROC, sobald Sie auf SQL2008 bekommen.

Beantwortet am 30/12/2009 um 04:06
quelle vom benutzer

stimmen
3

Was ich tun würde , ist CASEeinige Variablen am Anfang. Beispiel:

DECLARE
    @fooFlag int,
    @barFlag int,
    @bazFlag int,
    @quuxFlag int

SET @fooFlag = CASE WHEN @flag = 'foo' THEN 1 ELSE NULL END
SET @barFlag = CASE WHEN @flag = 'bar' THEN 1 ELSE NULL END
SET @bazFlag = CASE WHEN @flag = 'baz' THEN 1 ELSE NULL END
SET @quuxFlag = CASE WHEN @flag = 'quux' THEN 1 ELSE NULL END

SELECT ID, name, description, ...
FROM myTable
WHERE (fooFlag >= ISNULL(@fooFlag, 0) AND fooFlag <= ISNULL(@fooFlag, 1))
AND (barFlag >= ISNULL(@barFlag, 0) AND barFlag <= ISNULL(@barFlag, 1))
AND (bazFlag >= ISNULL(@bazFlag, 0) AND bazFlag <= ISNULL(@bazFlag, 1))
AND (quuxFlag >= ISNULL(@quuxFlag, 0) AND quuxFlag <= ISNULL(@quuxFlag, 1))

Die gute Sache über diese Frage ist, dass, weil die möglichen Werte für „Flags“ begrenzt sind, können Sie alle Ihre conditionals als Voraussetzungen statt Einwickeln Spalten in ihnen berechnen. Dies garantiert ein High-Performance-Index sucht auf welcher auch immer Spalten indiziert sind, und erfordert keine dynamische SQL schreiben. Und es ist besser als das Schreiben 4 separate Abfragen aus offensichtlichen Gründen.

Beantwortet am 30/12/2009 um 04:06
quelle vom benutzer

stimmen
0
where
   case when @value<>0 then Field else 1 end
   =
   case when @value<>0 then @value else 1 end
Beantwortet am 16/08/2016 um 10:24
quelle vom benutzer

stimmen
0
declare @CompanyID as varchar(10) = ''    -- or anyother value

select *  from EmployeeChatTbl chat

  where chat.ConversationDetails like '%'+@searchKey+'%' 

                and
                (
                    (0 = CASE WHEN (@CompanyID = '' ) THEN 0 ELSE 1 END) 
                                or 
                    (chat.CompanyID = @CompanyID)
                )

Arbeiten

wenn die CompanyID vorhanden ist, dann Filtration basierend auf es gemacht wird, andere weise, Filtration übersprungen.

Beantwortet am 06/03/2017 um 06:57
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more