SQL: clause IF dans la clause WHERE


203

Est-il possible d'utiliser une clause IF dans une clause WHERE dans MS SQL?

Exemple:

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

Réponses:


212

Utilisez une instruction CASE
UPDATE: la syntaxe précédente (comme l'ont souligné quelques personnes) ne fonctionne pas. Vous pouvez utiliser CASE comme suit:

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

Ou vous pouvez utiliser une instruction IF comme le souligne @ NJ Reed .


[Note après la MISE À JOUR par l'auteur]: Cela devrait fonctionner, mais vous devez TRIM () des deux côtés pour vous assurer qu'une correspondance est trouvée. J'ai l'intuition qu'il existe de rares cas encore marginaux qui ne correspondent pas.
Euro Micelli

1
L'utilisation CASEest la solution appropriée dans la plupart des cas. Dans mon cas, je voulais changer d'opérateur de comparaison et j'ai donc utilisé l'approche suivante.
Birla

142

Vous devriez pouvoir le faire sans IF ni CAS

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

Selon la version de SQL, vous devrez peut-être modifier les transtypages du numéro de commande en INT ou VARCHAR, selon que les transtypages implicites sont pris en charge.

Il s'agit d'une technique très courante dans une clause WHERE. Si vous souhaitez appliquer une logique "IF" dans la clause WHERE, tout ce que vous devez faire est d'ajouter la condition supplémentaire avec un booléen AND à la section où elle doit être appliquée.


2
J'imagine que vous prenez un peu plus de performances que la solution CASE, car toutes ces conditions sont évaluées, non?
Kevin Fairchild

J'oublie toujours qu'en SQL on peut remplacer les instructions conditionnelles par une logique booléenne comme ça. Merci pour le rappel, c'est une technique très utile!
CodexArcanum

1
Cette solution est en fait la meilleure en raison de la façon dont SQL Server traite la logique booléenne. Les instructions CASE dans les clauses where sont moins efficaces que les cas booléens car si la première vérification échoue, SQL arrêtera le traitement de la ligne et continuera. Cela vous fait gagner du temps de traitement. Aussi, mettez toujours la déclaration la plus coûteuse de l'autre côté de votre chèque booléen.
Steve

Merci pour une solution très élégante. Trouvé un didacticiel sur la méthode que vous avez utilisée qui peut aider les gens. weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
Rich

1
@Kash le lien que vous avez fourni est un registre à lire, existe-t-il une documentation accessible au public décrivant ce que vous dites?
Steve

29

Vous n'avez pas du tout besoin d'une instruction IF.

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

2
J'aime vraiment cette approche. Alternativ utilise: Filtre uniquement si AdmUseId a une valeur: where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) Ou filtre uniquement si IncludeDeleted = 0: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Kasper Halvas Jensen

Cela fonctionne bien lorsque vous utilisez un filtre IN dans la clause WHERE. Cela devient compliqué de le faire avec CASE car vous devez utiliser COALESCE et il est difficile à lire, alors que c'est une logique simple à lire. Instruction TSQL CASE dans la clause WHERE pour le filtre NOT IN ou IN
pholcroft

14

Il n'y a pas de bon moyen de le faire en SQL. Quelques approches que j'ai vues:

1) Utilisez CASE combiné avec des opérateurs booléens:

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) Utilisez des IF en dehors de SELECT

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

3) À l'aide d'une longue chaîne, composez votre instruction SQL de manière conditionnelle, puis utilisez EXEC

La 3ème approche est hideuse, mais c'est presque la seule pensée qui fonctionne si vous avez un certain nombre de conditions variables comme ça.


la quatrième approche consiste à convertir tous vos IF...ELSE...conditionnels en booléens ANDet ORcomme dans la réponse @ njr101 ci-dessus. L'inconvénient de ^ cette approche est qu'il peut être extrêmement difficile si vous en avez plusieurs IFou si vous en avez plusieurs qui sont imbriqués
Don Cheadle


4

Vous voulez l'instruction CASE

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

3

Je pense que là où ... comme / = ... cas ... alors ... peut fonctionner avec des booléens. J'utilise T-SQL.

Scénario: Supposons que vous souhaitiez obtenir les passe-temps de la personne 30 si le booléen est faux, et les passe-temps de la personne 42 si le booléen est vrai. (Selon certains, les recherches de passe-temps représentent plus de 90% des cycles de calcul de l'entreprise, alors payez une attention particulière.).

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
OERE (IsNumeric (@OrderNumber) <> 1 OU OrderNumber = @OrderNumber) 
             AND (IsNumber (@OrderNumber) = 1 OU OrderNumber LIKE '%' 
                                              + @OrderNumber + '%')

Règle de réécriture de forme normale conjonctive:IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
lorsque

1

La déclaration CASE est toujours meilleure que 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

En ligne, la condition fonctionnera correctement.


0

L'exemple suivant exécute une requête dans le cadre de l'expression booléenne, puis exécute des blocs d'instructions légèrement différents en fonction du résultat de l'expression booléenne. Chaque bloc d'instructions commence par BEGIN et se termine par 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

Utilisation d'instructions IF ... ELSE imbriquées L'exemple suivant montre comment une instruction IF… ELSE peut être imbriquée dans une autre. Définissez la variable @Number sur 5, 50 et 500 pour tester chaque instruction.

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
Cela ne semble pas pertinent. Il n'utilise pas un IF (ou tout code conditionnel) dans une clause WHERE.
Vince Bowdren

0

Dans le serveur SQL, j'ai eu le même problème, je voulais utiliser une instruction and uniquement si le paramètre est faux et sur true, je devais afficher les valeurs true et false, donc je l'ai utilisé de cette façon

(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 

Voyez si cela aide.


-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

Cela ne semble pas pertinent. Il n'utilise pas un IF (ou tout code conditionnel) dans une clause WHERE.
Vince Bowdren
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.