Comment effectuer un IF… THEN dans un SQL SELECT?

1508

Comment effectuer un IF...THENdans une SQL SELECTdéclaration?

Par exemple:

SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
Eric Labashosky
la source
14
Vous voudrez peut-être jeter un œil à ce lien . Concernant: Clauses SQL WHERE: Evitez CASE, utilisez la logique booléenne
Quelqu'un
3
@Quelqu'un: pas vraiment pertinent car l'article parle de l'utilisation de règles de réécriture logique pour convertir une implication en disjonction. L'indice est le mot «logique», c'est-à-dire quelque chose qui se résout à vrai ou faux, qui ne s'applique pas à la projection. TL; DR article applique WHEREet CHECKnon SELECT.
jour,
6
@ La réponse de MartinSmith est la plus élégante - utilisez IIF dans SQL 2012+.
Murray Foxcroft

Réponses:

1760

L' CASEinstruction est la plus proche de IF dans SQL et est prise en charge sur toutes les versions de SQL Server.

SELECT CAST(
             CASE
                  WHEN Obsolete = 'N' or InStock = 'Y'
                     THEN 1
                  ELSE 0
             END AS bit) as Saleable, *
FROM Product

Vous n'avez besoin de le faire que CASTsi vous voulez que le résultat soit une valeur booléenne. Si vous êtes satisfait d'un int, cela fonctionne:

SELECT CASE
            WHEN Obsolete = 'N' or InStock = 'Y'
               THEN 1
               ELSE 0
       END as Saleable, *
FROM Product

CASEles instructions peuvent être intégrées dans d'autres CASEinstructions et même incluses dans des agrégats.

SQL Server Denali (SQL Server 2012) ajoute l' instruction IIF qui est également disponible en accès (souligné par Martin Smith ):

SELECT IIF(Obsolete = 'N' or InStock = 'Y', 1, 0) as Saleable, * FROM Product
Darrel Miller
la source
57
Juste un mot de prudence supplémentaire ne mettez pas vos conditions dans des paniers lors de l'utilisation de l'étui. Il a fallu pas mal de temps pour réaliser cela :)
Archan Mishra
17
et n'oubliez pas la FIN
Simon_Weaver
8
et le bit AS!
Cas Bloem
8
Case, When, Else et End devraient être en retrait parallèles (le long de la même ligne) - et alors seulement devraient être en retrait plus vers l'intérieur - fonctionne le mieux pour moi.
Ujjwal Singh
6
@ReeveStrife uniquement si SQL Server 2012+
stuartdotnet
327

La déclaration de cas est votre ami dans cette situation et prend l'une des deux formes suivantes:

Le cas simple:

SELECT CASE <variable> WHEN <value>      THEN <returnvalue>
                       WHEN <othervalue> THEN <returnthis>
                                         ELSE <returndefaultcase>
       END AS <newcolumnname>
FROM <table>

Le cas étendu:

SELECT CASE WHEN <test>      THEN <returnvalue>
            WHEN <othertest> THEN <returnthis>
                             ELSE <returndefaultcase>
       END AS <newcolumnname>
FROM <table>

Vous pouvez même mettre des déclarations de cas dans une clause order by pour un classement vraiment sophistiqué.

Jonathan
la source
32
Je sais que c'est vieux, mais je pense qu'il convient de noter que vous pouvez ajouter un AS Col_Nameaprès le ENDpour nommer la colonne résultante
Ben
9
J'ai toujours l'impression que le 2e est plus simple.
Hogan
4
D'accord, je finis presque toujours par utiliser la déclaration de cas étendue car les conditions sur lesquelles je veux tester sont toujours plus complexes que la seule variable elle-même. Cela me semble également plus facile à lire.
magnum_pi
1
Bonne explication des deux situations, avec ou sans variable. Avec la variable, la condition doit satisfaire une égalité entre la variable après l'instruction case et celle sur laquelle vous basez votre condition, sans variable, vous pouvez ajouter une condition autosuffisante à tester.
Remus.A
Je suis plus pratique avec la deuxième option. Les deux sont tout aussi bien.
Stanley Okpala Nwosa
277

À partir de SQL Server 2012, vous pouvez utiliser la IIFfonction pour cela.

SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM   Product

Il s'agit en fait d'une manière d'écriture abrégée (bien que non standard SQL) CASE.

Je préfère la concision par rapport à la CASEversion étendue .

Les deux IIF()et CASErésolvent en tant qu'expressions dans une instruction SQL et ne peuvent être utilisés qu'à des endroits bien définis.

L'expression CASE ne peut pas être utilisée pour contrôler le flux d'exécution des instructions Transact-SQL, des blocs d'instructions, des fonctions définies par l'utilisateur et des procédures stockées.

Si vos besoins ne peuvent pas être satisfaits par ces limitations (par exemple, un besoin de renvoyer des jeux de résultats de forme différente en fonction d'une condition), SQL Server possède également un IFmot-clé procédural .

IF @IncludeExtendedInformation = 1
  BEGIN
      SELECT A,B,C,X,Y,Z
      FROM   T
  END
ELSE
  BEGIN
      SELECT A,B,C
      FROM   T
  END

Cependant, il faut parfois prendre soin d'éviter les problèmes de reniflage des paramètres avec cette approche .

Martin Smith
la source
6
Cela devrait être la réponse si vous voulez une instruction IF .. then en SQL.
Mr.J
91

Vous pouvez trouver de bons exemples dans The Power of SQL CASE Statements , et je pense que la déclaration que vous pouvez utiliser sera quelque chose comme ça (de 4guysfromrolla ):

SELECT
    FirstName, LastName,
    Salary, DOB,
    CASE Gender
        WHEN 'M' THEN 'Male'
        WHEN 'F' THEN 'Female'
    END
FROM Employees
sven
la source
4
voir: meta.stackexchange.com/questions/103053/… pour une discussion intéressante. Les deux liens que vous fournissez ajoutent du contexte supplémentaire, que je soutiens.
Sam Saffron
2
La référence est vraiment utile et fortement recommandée en cas de détails supplémentaires
baymax
75

Cas d'utilisation. Quelque chose comme ça.

SELECT Salable =
        CASE Obsolete
        WHEN 'N' THEN 1
        ELSE 0
    END
cheval pâle
la source
50
SELECT  
(CASE 
     WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
                                            ELSE 'NO' 
 END) as Salable
, * 
FROM Product
John Sheehan
la source
48

Microsoft SQL Server (T-SQL)

Dans un select, utilisez:

select case when Obsolete = 'N' or InStock = 'Y' then 'YES' else 'NO' end

Dans une whereclause, utilisez:

where 1 = case when Obsolete = 'N' or InStock = 'Y' then 1 else 0 end
user7658
la source
1
pourquoi ne pas simplement faire where Obsolete = 'N' or InStock = 'Y'et couper le où en deux pratiquement
maksymiuk
46

A partir de ce lien , nous pouvons comprendre IF THEN ELSEen T-SQL:

IF EXISTS(SELECT *
          FROM   Northwind.dbo.Customers
          WHERE  CustomerId = 'ALFKI')
  PRINT 'Need to update Customer Record ALFKI'
ELSE
  PRINT 'Need to add Customer Record ALFKI'

IF EXISTS(SELECT *
          FROM   Northwind.dbo.Customers
          WHERE  CustomerId = 'LARSE')
  PRINT 'Need to update Customer Record LARSE'
ELSE
  PRINT 'Need to add Customer Record LARSE' 

N'est-ce pas assez bon pour T-SQL?

Ken
la source
3
Ce n'est pas ce que le demandeur voulait, mais il est très utile de savoir que vous pouvez utiliser des instructions if en dehors d' une instruction select.
Jonathan
2
EXISTS est bon car il se libère de la boucle de recherche si un élément est trouvé. Un COUNT s'exécute jusqu'à la fin des lignes du tableau. Rien à voir avec la question, mais quelque chose à savoir.
JustJohn
45
 SELECT
   CASE 
      WHEN OBSOLETE = 'N' or InStock = 'Y' THEN 'TRUE' 
      ELSE 'FALSE' 
   END AS Salable,
   * 
FROM PRODUCT
Santiago Cepas
la source
32

Instruction if-else simple dans SQL Server:

DECLARE @val INT;
SET @val = 15;

IF @val < 25
PRINT 'Hi Ravi Anand';
ELSE
PRINT 'By Ravi Anand.';

GO

Instruction Nested If ... else dans SQL Server -

DECLARE @val INT;
SET @val = 15;

IF @val < 25
PRINT 'Hi Ravi Anand.';
ELSE
BEGIN
IF @val < 50
  PRINT 'what''s up?';
ELSE
  PRINT 'Bye Ravi Anand.';
END;

GO
Ravi Anand
la source
2
Tard mais est-il utilisable à l'intérieur SELECTcomme l'OP l'a demandé?
abdul qayyum
25

Une nouvelle fonctionnalité, IIF (que nous pouvons simplement utiliser), a été ajoutée dans SQL Server 2012:

SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
sandeep rawat
la source
1
Cette réponse reprend (avec moins de détails) ce qui était déjà fourni dans la réponse de Martin Smith il y a plusieurs années.
jk7
1
@ jk7 c'était la première réponse à la question.
sandeep rawat
3
Pas d'après ce que je vois. Il est écrit que votre réponse a été publiée le 26 avril 16 et celle de Martin le 20 juillet 2011.
jk7
24

Utilisez une instruction CASE:

SELECT CASE
       WHEN (Obsolete = 'N' OR InStock = 'Y')
       THEN 'Y'
       ELSE 'N'
END as Available

etc...
Krizzy
la source
23

Utilisez une logique de bits purs:

DECLARE @Product TABLE (
    id INT PRIMARY KEY IDENTITY NOT NULL
   ,Obsolote CHAR(1)
   ,Instock CHAR(1)
)

INSERT INTO @Product ([Obsolote], [Instock])
    VALUES ('N', 'N'), ('N', 'Y'), ('Y', 'Y'), ('Y', 'N')

;
WITH cte
AS
(
    SELECT
        'CheckIfInstock' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Instock], 'Y'), 1), 'N'), 0) AS BIT)
       ,'CheckIfObsolote' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Obsolote], 'N'), 0), 'Y'), 1) AS BIT)
       ,*
    FROM
        @Product AS p
)
SELECT
    'Salable' = c.[CheckIfInstock] & ~c.[CheckIfObsolote]
   ,*
FROM
    [cte] c

Voir la démonstration de travail: si alors sans casedans SQL Server .

Pour commencer, vous devez déterminer la valeur de trueet falsepour les conditions sélectionnées. Voici deux NULLIF :

for true: ISNULL(NULLIF(p.[Instock], 'Y'), 1)
for false: ISNULL(NULLIF(p.[Instock], 'N'), 0)

combinés ensemble donne 1 ou 0. Ensuite, utilisez des opérateurs au niveau du bit .

C'est la méthode la plus WYSIWYG .

Tomasito
la source
19
-1 pour l'obscurcissement de code. Sérieusement, c'est à peu près aussi loin que possible de WYSIWYG! Un bordel rouge et illisible, et si je devais travailler sur votre code, je maudirais toute la journée ... désolé: - /
Heliac
2
@Heliac a mis cte part dans View et vous ne verrez jamais le bordel. Pour les longs et compliqués ET, OU, ce n'est pas plus lisible que CASE (cette partie en dehors de cte bien sûr).
Tomasito
1
Je lui ai donné un +1 pour la netteté, une fois qu'il est dans un cte, mais notez que la réponse est actuellement incorrecte pour la question. Vous avez besoin d'un '|' pas un '&'.
Mark Hurd
3
Tout à fait d'accord avec @Heliac. Bien qu'il soit syntaxiquement correct et fonctionne correctement, il n'est tout simplement pas facilement supportable. Le placer dans un CTE ne fera que déplacer ce morceau de code illisible ailleurs.
objectNotFound
1
La méthode de vérification de combinaison par table pourrait avoir ses avantages. Utiliser une variable de table et la joindre à la requête existante pourrait fournir une solution basée sur un ensemble sans cas. Cette réponse est un mauvais exemple, mais l'idée de table elle-même a du mérite.
Suncat2000
19
SELECT 1 AS Saleable, *
  FROM @Product
 WHERE ( Obsolete = 'N' OR InStock = 'Y' )
UNION
SELECT 0 AS Saleable, *
  FROM @Product
 WHERE NOT ( Obsolete = 'N' OR InStock = 'Y' )
un jour
la source
17
SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END as newref
From profile
atik sarker
la source
Peux-tu élaborer?
Peter Mortensen
14
case statement some what similar to if in SQL server

SELECT CASE 
            WHEN Obsolete = 'N' or InStock = 'Y' 
               THEN 1 
               ELSE 0 
       END as Saleable, * 
FROM Product
Chanukya
la source
2
Pourriez-vous expliquer comment cela répond à la question posée?
Guanxi
@Guanxi: bien que ce ne soit pas ma réponse, un «cas» généralise un «si-alors-autre» (de 2 cas à plusieurs)
JosephDoggie
Peux-tu élaborer?
Peter Mortensen
13

Ce n'est pas une réponse, juste un exemple d'une instruction CASE utilisée lorsque je travaille. Il a une instruction CASE imbriquée. Maintenant tu sais pourquoi mes yeux sont croisés.

 CASE orweb2.dbo.Inventory.RegulatingAgencyName
    WHEN 'Region 1'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'Region 2'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'Region 3'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'DEPT OF AGRICULTURE'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactAg
    ELSE (
            CASE orweb2.dbo.CountyStateAgContactInfo.IsContract
                WHEN 1
                    THEN orweb2.dbo.CountyStateAgContactInfo.ContactCounty
                ELSE orweb2.dbo.CountyStateAgContactInfo.ContactState
                END
            )
    END AS [County Contact Name]
JustJohn
la source
1
L'édition qui a reformaté les instructions Case est fine et dandy et la rend plus compréhensible, mais le SQL continuerait de se regrouper dans la vue qui l'utilise.
JustJohn
1
Je me CASEdemande juste pourquoi devenir voté et marqué comme une réponse au lieu de ce IFqui aurait dû être la réponse, comme celle-ci, c'est toujours une CASEdéclaration, pas une IF.
Mr.J
@ Mr.J: bien que ce ne soit pas ma réponse, un «cas» généralise un «si-alors-autre» (de 2 cas à plusieurs)
JosephDoggie
12

Si vous insérez des résultats dans une table pour la première fois, plutôt que de transférer des résultats d'une table à une autre, cela fonctionne dans Oracle 11.2g:

INSERT INTO customers (last_name, first_name, city)
    SELECT 'Doe', 'John', 'Chicago' FROM dual
    WHERE NOT EXISTS 
        (SELECT '1' from customers 
            where last_name = 'Doe' 
            and first_name = 'John'
            and city = 'Chicago');
Robert B. Grossman
la source
4
les balises disent SQL Server, TSQL
Malachi
11

Comme solution alternative à la CASEdéclaration, une approche basée sur les tables peut être utilisée:

DECLARE @Product TABLE (ID INT, Obsolete VARCHAR(10), InStock VARCHAR(10))
INSERT INTO @Product VALUES
(1,'N','Y'),
(2,'A','B'),
(3,'N','B'),
(4,'A','Y')

SELECT P.* , ISNULL(Stmt.Saleable,0) Saleable
FROM
    @Product P
    LEFT JOIN
        ( VALUES
            ( 'N', 'Y', 1 )
        ) Stmt (Obsolete, InStock, Saleable)
        ON  P.InStock = Stmt.InStock OR P.Obsolete = Stmt.Obsolete

Résultat:

ID          Obsolete   InStock    Saleable
----------- ---------- ---------- -----------
1           N          Y          1
2           A          B          0
3           N          B          1
4           A          Y          1
Serkan Arslan
la source
Vendable est utilisé dans où condition dans la requête?
Bhavin Thummar
Il peut être utilisé dans quel état.
Serkan Arslan
9
SELECT CASE WHEN Obsolete = 'N' or InStock = 'Y' THEN 1 ELSE 0 
             END AS Saleable, * 
FROM Product

la source
6

Pour ceux qui utilisent SQL Server 2012, IIF est une fonctionnalité qui a été ajoutée et fonctionne comme une alternative aux instructions Case.

SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM   Product 
Dibin
la source
1
Cette réponse reprend (avec moins de détails) ce qui était déjà fourni dans la réponse de Martin Smith il y a plusieurs années.
jk7
6
  SELECT IIF(Obsolete = 'N' OR InStock = 'Y',1,0) AS Saleable, * FROM Product
SURJEET SINGH Bisht
la source
7
Salut Surjeet Singh Bisht; votre code pourrait être correct, mais avec un certain contexte, il ferait une meilleure réponse; par exemple, vous pourriez expliquer comment et pourquoi cette modification proposée résoudrait le problème de l'interrogateur, peut-être en incluant un lien vers la documentation pertinente. Cela les rendrait plus utiles pour eux, et aussi plus utiles aux autres lecteurs de sites qui recherchent des solutions à des problèmes similaires.
Vince Bowdren
5
Cette réponse n'ajoute rien de nouveau. En fait, cette même ligne exacte fait partie de la réponse acceptée depuis plus de 5 ans .
SL Barth - Rétablir Monica
1
De plus, il est important de mentionner que l' IIF ne s'applique qu'à SQL Server à partir de 2012
Ivan Rascon
5

Vous pouvez avoir deux choix pour que cela soit réellement implémenté:

  1. En utilisant IIF, qui a été introduit à partir de SQL Server 2012:

    SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
  2. En utilisant Select Case:

    SELECT CASE
        WHEN Obsolete = 'N' or InStock = 'Y'
            THEN 1
            ELSE 0
        END as Saleable, *
        FROM Product
Peter Mortensen
la source
4

Question:

SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product

ANSI:

Select 
  case when p.Obsolete = 'N' 
  or p.InStock = 'Y' then 1 else 0 end as Saleable, 
  p.* 
FROM 
  Product p;

L'utilisation d'alias - pdans ce cas - permettra d'éviter les problèmes.

David Cohn
la source
3

L'utilisation de SQL CASE est similaire aux instructions If / Else normales. Dans la requête ci-dessous, si la valeur obsolète = 'N' ou si la valeur InStock = 'Y', alors la sortie sera 1. Sinon, la sortie sera 0. Ensuite, nous mettons cette valeur 0 ou 1 sous la colonne vendable.

SELECT
      CASE 
        WHEN obsolete = 'N' OR InStock = 'Y' 
        THEN 1 
        ELSE 0 
      END AS Salable
      , * 
FROM PRODUCT
Tharuka
la source
1
Ça m'a l'air bien. Peut-être un mot ou deux pour l'expliquer?
JQSOFT
C'est exactement comme les instructions If / Else normales. Si la valeur obsolète = 'N' ou Si la valeur InStock = 'Y', alors la sortie sera 1. Sinon, la sortie sera 0.
Tharuka
1
Je vous remercie. Veuillez modifier votre message pour ajouter cette explication. Comme: Les If..Then...Else..instructions sont utilisées SQLcomme suit ....
JQSOFT
2
SELECT 
  CAST(
    CASE WHEN Obsolete = 'N' 
    or InStock = 'Y' THEN ELSE 0 END AS bit
  ) as Saleable, * 
FROM 
  Product
gii96
la source
8
De l'avis: Welcome to Stack Overflow! Veuillez ne pas répondre uniquement avec le code source. Essayez de fournir une belle description du fonctionnement de votre solution. Voir: Comment écrire une bonne réponse? . Merci
sɐunıɔ ןɐ qɐp
3
Je pense que vous constaterez que cela ne s'exécute pas, car il manque toute sortie suivant le mot-clé 'ALORS'.
Dodecaphone du
Peux-tu élaborer?
Peter Mortensen
2

Ce sera quelque chose comme ça:

SELECT OrderID, Quantity,
CASE
    WHEN Quantity > 30 THEN "The quantity is greater than 30"
    WHEN Quantity = 30 THEN "The quantity is 30"
    ELSE "The quantity is under 30"
END AS QuantityText
FROM OrderDetails;
Muhammad Awais
la source
Pouvons-nous utiliser la valeur QuantityText dans la condition Where d'une requête? par exempleSELECT OrderID, Quantity, CASE WHEN Quantity > 30 THEN "The quantity is greater than 30" WHEN Quantity = 30 THEN "The quantity is 30" ELSE "The quantity is under 30" END AS QuantityText FROM OrderDetails WHERE QuantityText = 'The quantity is 30';
Bhavin Thummar
1

Par souci d'exhaustivité, j'ajouterais que SQL utilise une logique à trois valeurs. L'expression:

obsolete = 'N' OR instock = 'Y'

Pourrait produire trois résultats distincts:

| obsolete | instock | saleable |
|----------|---------|----------|
| Y        | Y       | true     |
| Y        | N       | false    |
| Y        | null    | null     |
| N        | Y       | true     |
| N        | N       | true     |
| N        | null    | true     |
| null     | Y       | true     |
| null     | N       | null     |
| null     | null    | null     |

Ainsi, par exemple, si un produit est obsolète mais que vous ne savez pas si le produit est en stock, vous ne savez pas si le produit est vendable. Vous pouvez écrire cette logique à trois valeurs comme suit:

SELECT CASE
           WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
           WHEN NOT (obsolete = 'N' OR instock = 'Y') THEN 'false'
           ELSE NULL
       END AS saleable

Une fois que vous avez compris comment cela fonctionne, vous pouvez convertir trois résultats en deux résultats en décidant du comportement de null. Par exemple, cela traiterait null comme non vendable:

SELECT CASE
           WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
           ELSE 'false' -- either false or null
       END AS saleable
Salman A
la source
0

J'aime l'utilisation des instructions CASE mais la question demandait une instruction IF dans le SQL Select. Ce que j'ai utilisé dans le passé a été:

SELECT

   if(GENDER = "M","Male","Female") as Gender

FROM ...

C'est comme les instructions IF Excel ou Sheet où il y a une conditionnelle suivie de la vraie condition puis de la fausse condition:

if(condition, true, false)

De plus, vous pouvez imbriquer les instructions if (mais alors utiliser doit utiliser un CASE :-)

(Remarque: cela fonctionne dans MySQLWorkbench mais peut ne pas fonctionner sur d'autres plates-formes)

Prashant Marathay
la source
0

Vous pouvez utiliser la déclaration de cas:

Select 
Case WHEN (Obsolete = 'N' or InStock = 'Y') THEN 1 ELSE 0 END Saleable,
Product.*
from Product
akanksha gupta
la source