SQL: IF-Klausel innerhalb der WHERE-Klausel


203

Ist es möglich, eine IF- Klausel innerhalb einer WHERE- Klausel in MS SQL zu verwenden?

Beispiel:

WHERE
    IF IsNumeric(@OrderNumber) = 1
        OrderNumber = @OrderNumber
    ELSE
        OrderNumber LIKE '%' + @OrderNumber + '%'

Antworten:


212

Verwenden Sie eine CASE- Anweisung.
UPDATE: Die vorherige Syntax (auf die einige Leute hingewiesen haben) funktioniert nicht. Sie können CASE wie folgt verwenden:

WHERE OrderNumber LIKE
  CASE WHEN IsNumeric(@OrderNumber) = 1 THEN 
    @OrderNumber 
  ELSE
    '%' + @OrderNumber
  END

Oder Sie können eine IF-Anweisung verwenden, wie @ NJ Reed hervorhebt.


[Anmerkung nach dem UPDATE nach Autor]: Das sollte funktionieren, aber Sie sollten beide Seiten TRIM (), um sicherzustellen, dass eine Übereinstimmung gefunden wird. Ich habe das Gefühl, dass es seltene Fälle gibt, die immer noch nicht übereinstimmen.
Euro Micelli

1
CASEIn den meisten Fällen ist die Verwendung die geeignete Lösung. In meinem Fall wollte ich den Vergleichsoperator ändern und habe daher den nächsten Ansatz verwendet.
Birla

142

Sie sollten dies ohne IF oder CASE tun können

 WHERE 
   (IsNumeric(@OrderNumber) AND
      (CAST OrderNumber AS VARCHAR) = (CAST @OrderNumber AS VARCHAR)
 OR
   (NOT IsNumeric(@OrderNumber) AND
       OrderNumber LIKE ('%' + @OrderNumber))

Abhängig von der SQL-Variante müssen Sie möglicherweise die Casts auf der Bestellnummer auf INT oder VARCHAR anpassen, je nachdem, ob implizite Casts unterstützt werden.

Dies ist eine sehr häufige Technik in einer WHERE-Klausel. Wenn Sie eine "IF" -Logik in der WHERE-Klausel anwenden möchten, müssen Sie lediglich die zusätzliche Bedingung mit einem booleschen UND zu dem Abschnitt hinzufügen, in dem sie angewendet werden muss.


2
Ich würde mir vorstellen, dass Sie einen kleinen Leistungseinbruch gegenüber der CASE-Lösung hinnehmen, da all diese Bedingungen bewertet werden, nicht wahr?
Kevin Fairchild

Ich vergesse immer, dass man in SQL bedingte Anweisungen durch solche boolesche Logik ersetzen kann. Vielen Dank für die Erinnerung, es ist eine sehr nützliche Technik!
CodexArcanum

1
Diese Lösung ist tatsächlich die beste, da SQL Server die boolesche Logik verarbeitet. CASE-Anweisungen, bei denen Klauseln weniger effizient sind als boolesche Fälle, da SQL die Verarbeitung der Zeile beendet und fortfährt, wenn die erste Prüfung fehlschlägt. Das spart Ihnen Bearbeitungszeit. Stellen Sie außerdem die teurere Aussage immer auf die andere Seite Ihres Booleschen Checks.
Steve

Vielen Dank für eine sehr elegante Lösung. Es wurde ein Tutorial zu der von Ihnen verwendeten Methode gefunden, das Menschen helfen kann. weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
Rich

1
@Kash Der von Ihnen bereitgestellte Link ist ein Register zum Lesen. Gibt es eine öffentlich zugängliche Dokumentation, die beschreibt, was Sie sagen?
Steve

29

Sie brauchen überhaupt keine IF-Anweisung.

WHERE
    (IsNumeric(@OrderNumber) = 1 AND OrderNumber = @OrderNumber)
OR (IsNumeric(@OrderNumber) = 0 AND OrderNumber LIKE '%' + @OrderNumber + '%')

2
Ich mag diesen Ansatz wirklich. Alternativ verwendet: Nur filtern, wenn AdmUseId einen Wert hat: where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) Oder nur filtern, wenn IncludeDeleted = 0: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Kasper Halvas Jensen

Dies funktioniert gut, wenn ein IN-Filter innerhalb der WHERE-Klausel verwendet wird. Bei CASE wird dies zu Problemen, da Sie COALESCE verwenden müssen und es schwer zu lesen ist, während dies eine einfache Logik zum Lesen ist. TSQL CASE-Anweisung in der WHERE-Klausel für NOT IN- oder IN-Filter
pholcroft

14

In SQL gibt es keine gute Möglichkeit, dies zu tun. Einige Ansätze, die ich gesehen habe:

1) Verwenden Sie CASE in Kombination mit booleschen Operatoren:

WHERE
    OrderNumber = CASE 
        WHEN (IsNumeric(@OrderNumber) = 1)
        THEN CONVERT(INT, @OrderNumber)
        ELSE -9999 -- Some numeric value that just cannot exist in the column
    END
    OR 
    FirstName LIKE CASE
        WHEN (IsNumeric(@OrderNumber) = 0)
        THEN '%' + @OrderNumber
        ELSE ''
    END

2) Verwenden Sie IFs außerhalb von SELECT

IF (IsNumeric(@OrderNumber)) = 1
BEGIN
    SELECT * FROM Table
    WHERE @OrderNumber = OrderNumber
END ELSE BEGIN
    SELECT * FROM Table
    WHERE OrderNumber LIKE '%' + @OrderNumber
END

3) Verfassen Sie Ihre SQL-Anweisung mit einer langen Zeichenfolge unter bestimmten Bedingungen und verwenden Sie dann EXEC

Der dritte Ansatz ist abscheulich, aber es ist fast der einzige Gedanke, der funktioniert, wenn Sie eine Reihe von variablen Bedingungen wie diese haben.


der vierte Ansatz ist es, alle Ihre konvertieren IF...ELSE...conditionals in boolean AND‚s und OR‘ s wie in @ njr101 Antwort oben. Der Nachteil dieses Ansatzes ist, dass es schwierig sein kann, wenn Sie viele haben IFoder wenn viele verschachtelt sind
Don Cheadle


4

Sie möchten die CASE-Anweisung

WHERE OrderNumber LIKE
CASE WHEN IsNumeric(@OrderNumber)=1 THEN @OrderNumber ELSE '%' + @OrderNumber END

3

Ich denke, wo ... wie / = ... Fall ... dann ... mit Booleschen Werten arbeiten kann. Ich benutze T-SQL.

Szenario: Angenommen, Sie möchten die Hobbys von Person-30 erhalten, wenn bool falsch ist, und die Hobbys von Person-42, wenn bool wahr ist. (Laut einigen machen Hobby-Lookups über 90% der Geschäftsberechnungszyklen aus, zahlen Sie also genau.)

CREATE PROCEDURE sp_Case
@bool   bit
AS
SELECT Person.Hobbies
FROM Person
WHERE Person.ID = 
    case @bool 
        when 0 
            then 30
        when 1
            then 42
    end;

2
WHERE (IsNumeric (@OrderNumber) <> 1 OR OrderNumber = @OrderNumber) 
             AND (IsNumber (@OrderNumber) = 1 ODER OrderNumber LIKE '%' 
                                              + @OrderNumber + '%')

Konjunktive Normalform Umschreibungsregel:IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
Tag, wenn

1

CASE Statement ist immer eine bessere Option als IF .

  WHERE  vfl.CreatedDate >= CASE WHEN @FromDate IS NULL THEN vfl.CreatedDate ELSE  @FromDate END
    AND vfl.CreatedDate<=CASE WHEN @ToDate IS NULL THEN vfl.CreatedDate ELSE @ToDate END 

1
    WHERE OrderNumber LIKE CASE WHEN IsNumeric(@OrderNumber) = 1 THEN @OrderNumber ELSE  '%' + @OrderNumber END

In diesem Fall funktioniert der Zustand ordnungsgemäß.


0

Im folgenden Beispiel wird eine Abfrage als Teil des Booleschen Ausdrucks ausgeführt und anschließend basierend auf dem Ergebnis des Booleschen Ausdrucks geringfügig andere Anweisungsblöcke ausgeführt. Jeder Anweisungsblock beginnt mit BEGIN und endet mit END.

USE AdventureWorks2012;
GO
DECLARE @AvgWeight decimal(8,2), @BikeCount int
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
BEGIN
   SET @BikeCount = 
        (SELECT COUNT(*) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   SET @AvgWeight = 
        (SELECT AVG(Weight) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   PRINT 'There are ' + CAST(@BikeCount AS varchar(3)) + ' Touring-3000 bikes.'
   PRINT 'The average weight of the top 5 Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.';
END
ELSE 
BEGIN
SET @AvgWeight = 
        (SELECT AVG(Weight)
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%' );
   PRINT 'Average weight of the Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.' ;
END ;
GO

Verwenden verschachtelter IF ... ELSE-Anweisungen Das folgende Beispiel zeigt, wie eine IF ... ELSE-Anweisung in einer anderen verschachtelt werden kann. Setzen Sie die Variable @Number auf 5, 50 und 500, um jede Anweisung zu testen.

DECLARE @Number int
SET @Number = 50
IF @Number > 100
   PRINT 'The number is large.'
ELSE 
   BEGIN
      IF @Number < 10
      PRINT 'The number is small'
   ELSE
      PRINT 'The number is medium'
   END ;
GO

2
Dies scheint nicht relevant zu sein. In einer WHERE-Klausel wird kein IF (oder ein bedingter Code) verwendet.
Vince Bowdren

0

In SQL Server hatte ich das gleiche Problem, dass ich eine and-Anweisung nur verwenden wollte, wenn der Parameter false ist, und bei true musste ich beide Werte true und false anzeigen, damit ich sie auf diese Weise verwendete

(T.IsPublic = @ShowPublic or  @ShowPublic = 1)

-1
If @LstTransDt is Null
                begin
                    Set @OpenQty=0
                end
            else
                begin
                   Select   @OpenQty=IsNull(Sum(ClosingQty),0)  
                   From  ProductAndDepotWiseMonitoring  
                   Where   Pcd=@PCd And PtpCd=@PTpCd And TransDt=@LstTransDt      
                end 

Sehen Sie, ob dies hilft.


-6
USE AdventureWorks2012;
GO
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
PRINT 'There are more than 5 Touring-3000 bicycles.'
ELSE PRINT 'There are 5 or less Touring-3000 bicycles.' ;
GO

Dies scheint nicht relevant zu sein. In einer WHERE-Klausel wird kein IF (oder ein bedingter Code) verwendet.
Vince Bowdren
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.