Come eseguo un IF ... THEN in un SQL SELECT?


1508

Come eseguo un'istruzione IF...THENin SQL SELECT?

Per esempio:

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

14
Potresti dare un'occhiata a questo link . Riguardo a: clausole WHERE di SQL: evitare CASE, utilizzare la logica booleana
Qualcuno

3
@Somebody: non molto rilevante perché l'articolo parla dell'utilizzo di regole di riscrittura logica per convertire un'implicazione in una disgiunzione. L'indizio è la parola "logica", ovvero qualcosa che si risolve in vero o falso, che non si applica alla proiezione. TL; DR articolo si applica a WHEREe CHECK, ma non SELECT.
onedayquando

6
La risposta di @ MartinSmith è la più elegante: usa IIF in SQL 2012+.
Murray Foxcroft,

Risposte:


1760

Il CASE istruzione è la più vicina a IF in SQL ed è supportata su tutte le versioni di SQL Server.

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

Devi solo fare ciò CASTse vuoi il risultato come valore booleano. Se sei soddisfatto di un int, questo funziona:

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

CASEle istruzioni possono essere incorporate in altre CASEistruzioni e persino incluse negli aggregati.

SQL Server Denali (SQL Server 2012) aggiunge l' istruzione IIF che è anche disponibile in accesso (sottolineato da Martin Smith ):

SELECT IIF(Obsolete = 'N' or InStock = 'Y', 1, 0) as Saleable, * FROM Product

57
Solo un'ulteriore avvertenza non racchiude le tue condizioni tra parentesi quando si utilizza la custodia. Ci è voluto un bel po 'di tempo per rendersene conto :)
Archan Mishra,

17
e non dimenticare la FINE
Simon_Weaver,

8
e il bit AS!
Cas Bloem,

8
Case, When, Else ed End dovrebbero essere rientrati in parallelo (lungo la stessa linea) - e solo allora dovrebbero essere rientrati più all'interno - funziona meglio per me.
Ujjwal Singh,

6
@ReeveStrife Solo se SQL Server 2012+
stuartdotnet

327

L'affermazione del caso è tua amica in questa situazione e assume una delle due forme:

Il semplice caso:

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

Il caso esteso:

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

Puoi anche mettere le dichiarazioni dei casi in un ordine per clausola per un ordinamento davvero fantasioso.


32
So che questo è vecchio, ma penso che dovrebbe essere notato che è possibile aggiungere un AS Col_Namedopo il ENDdare un nome colonna risultante
Ben

9
Ho sempre la sensazione che il secondo sia più semplice.
Hogan,

4
D'accordo, finisco quasi sempre con l'istruzione case estesa perché le condizioni su cui voglio testare sono sempre più complesse della sola variabile stessa. Mi sembra anche più facile da leggere.
magnum_pi,

1
Buona spiegazione di entrambe le situazioni, con o senza variabile. Con la variabile la condizione deve soddisfare un'uguaglianza tra la variabile dopo l'istruzione case e quella su cui si basa la propria condizione, senza la variabile è possibile aggiungere una condizione autosufficiente per il test.
Remus.A

Sono più a mio agio con la seconda opzione. I due stanno ugualmente bene.
Stanley Okpala Nwosa,

277

Da SQL Server 2012 è possibile utilizzare la IIFfunzione per questo.

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

Questo è effettivamente solo un modo di scrivere abbreviato (anche se non standard SQL) CASE .

Preferisco la concisione rispetto all'espanso CASE versione .

Sia IIF()e CASEdeterminazione come espressioni all'interno di un'istruzione SQL e può essere utilizzato solo in luoghi ben definiti.

L'espressione CASE non può essere utilizzata per controllare il flusso di esecuzione di istruzioni Transact-SQL, blocchi di istruzioni, funzioni definite dall'utente e procedure memorizzate.

Se queste esigenze non possono essere soddisfatte da queste limitazioni (ad esempio, la necessità di restituire set di risultati di forma diversa in base a una condizione), anche SQL Server dispone di una IFparola chiave procedurale .

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

Tuttavia, a volte è necessario prestare attenzione per evitare problemi di sniffing dei parametri con questo approccio .


6
Questa dovrebbe essere la risposta se vuoi un'istruzione IF .. then in SQL.
Mr.J

91

Puoi trovare alcuni begli esempi in The Power of SQL CASE Statements , e penso che l'affermazione che puoi usare sarà qualcosa del genere (da 4guysfromrolla ):

SELECT
    FirstName, LastName,
    Salary, DOB,
    CASE Gender
        WHEN 'M' THEN 'Male'
        WHEN 'F' THEN 'Female'
    END
FROM Employees

4
vedi: meta.stackexchange.com/questions/103053/… per una discussione interessante. I due collegamenti forniti aggiungono un contesto aggiuntivo, che io sostengo.
Sam Saffron,

2
Il riferimento è davvero utile e altamente raccomandato in caso di ulteriori dettagli
baymax

75

Caso d'uso. Qualcosa come questo.

SELECT Salable =
        CASE Obsolete
        WHEN 'N' THEN 1
        ELSE 0
    END

50
SELECT  
(CASE 
     WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
                                            ELSE 'NO' 
 END) as Salable
, * 
FROM Product

48

Microsoft SQL Server (T-SQL)

In a select, utilizzare:

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

In una whereclausola, utilizzare:

where 1 = case when Obsolete = 'N' or InStock = 'Y' then 1 else 0 end

1
perché non dovresti semplicemente fare where Obsolete = 'N' or InStock = 'Y'e tagliare il punto a metà praticamente
maksymiuk il

46

Da questo link , possiamo capire IF THEN ELSEin 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' 

Non è abbastanza buono per T-SQL?


3
Questo non è ciò che il richiedente voleva, ma è molto utile sapere che è possibile utilizzare le istruzioni all'esterno di un'istruzione select.
Jonathan,

2
EXISTS è utile perché viene eliminato dal ciclo di ricerca se viene trovato un elemento. Un COUNT viene eseguito fino alla fine delle righe della tabella. Niente a che fare con la domanda, ma qualcosa da sapere.
JustJohn,

45
 SELECT
   CASE 
      WHEN OBSOLETE = 'N' or InStock = 'Y' THEN 'TRUE' 
      ELSE 'FALSE' 
   END AS Salable,
   * 
FROM PRODUCT

32

Istruzione if-else semplice in SQL Server:

DECLARE @val INT;
SET @val = 15;

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

GO

Istruzione nidificata If ... else in 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

2
In ritardo ma è utilizzabile all'interno SELECTcome richiesto da OP?
Abdul Qayyum,

25

Una nuova funzionalità, IIF (che possiamo semplicemente usare), è stata aggiunta in SQL Server 2012:

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

1
Questa risposta ripete (con meno dettagli) ciò che era già stato fornito nella risposta di Martin Smith diversi anni fa.
jk7

1
@ jk7 questa è stata la prima risposta alla domanda.
sandeep rawat

3
Non da quello che vedo. Dice che la tua risposta è stata pubblicata il 26 aprile 16 e quella di Martin è stata pubblicata il 20 luglio 11.
jk7

24

Utilizzare un'istruzione CASE:

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

etc...

23

Usa logica bit pura:

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

Guarda la demo funzionante: se poi senza caseSQL Server .

Per iniziare, è necessario calcolare il valore di truee falseper le condizioni selezionate. Ecco due NULLIF :

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

combinato insieme dà 1 o 0. Operatori bit per bit successivi .

È il metodo più WYSIWYG .


19
-1 per Offuscamento codice. Seriamente, questo è il più lontano possibile da WYSIWYG! Un disordinato pasticcio illeggibile, e se dovessi lavorare sul tuo codice, avrei maledetto tutto il giorno ... scusa: - /
Heliac il

2
@Heliac ha messo la parte cte in View e non vedrai mai il casino. Per lungo e complicato AND, O, NON è più leggibile di CASE (quella parte al di fuori del cte ovviamente).
Tomasito,

1
Ho dato questo un +1 per la pulizia, una volta che è in un cte, ma nota che la risposta è attualmente sbagliata per la domanda. Hai bisogno di un '|' non un '&'.
Mark Hurd,

3
Totalmente d'accordo con @Heliac. Sebbene sia sintatticamente corretto e funzioni bene, non è facilmente sopportabile. Metterlo in un CTE sposta semplicemente quel pezzo di codice non leggibile da qualche altra parte.
objectNotFound

1
Il metodo tabella di controllo della combinazione potrebbe avere i suoi vantaggi. L'uso di una variabile di tabella e l'unione alla query esistente potrebbe fornire una soluzione basata su set senza un caso. Questa risposta è un cattivo esempio, ma l'idea della tabella stessa ha valore.
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' )


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

2
Potresti per favore dare qualche spiegazione su come questo risponde alla domanda posta?
Guanxi,

@Guanxi: sebbene non sia la mia risposta, un 'caso' generalizza un 'if-then-else' (da 2 casi a molti)
JosephDoggie,

Puoi elaborare?
Peter Mortensen,

13

Questa non è una risposta, solo un esempio di una dichiarazione CASE in uso dove lavoro. Ha un'istruzione CASE nidificata. Ora sai perché i miei occhi sono incrociati.

 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]

1
La modifica che ha riformattato le istruzioni Case è perfetta e dandy e la rende più comprensibile, ma l'SQL rimarrebbe comunque tutto sommato nella vista che la sta usando.
JustJohn,

1
Sto solo vagando perché CASEdiventare votato e contrassegnato come risposta anzichéIF che quale avrebbe dovuto essere la risposta, come questa, questa è ancora CASEun'affermazione, non una IF.
Mr.J

@ Mr.J: sebbene non sia la mia risposta, un 'caso' generalizza un 'if-then-else' (da 2 casi a molti)
JosephDoggie,

12

Se stai inserendo i risultati in una tabella per la prima volta, anziché trasferirli da una tabella all'altra, questo funziona in 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');

4
i tag dicono SQL Server, TSQL
Malachi il

11

Come soluzione alternativa a CASE all'istruzione, è possibile utilizzare un approccio basato su tabella:

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

Risultato:

ID          Obsolete   InStock    Saleable
----------- ---------- ---------- -----------
1           N          Y          1
2           A          B          0
3           N          B          1
4           A          Y          1

Vendibile viene utilizzato in cui condizione nella query?
Bhavin Thummar,

Può essere utilizzato in qualsiasi condizione.
Serkan Arslan,

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

6

Per coloro che utilizzano SQL Server 2012, IIF è una funzionalità che è stata aggiunta e funziona in alternativa alle istruzioni Case.

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

1
Questa risposta ripete (con meno dettagli) ciò che era già stato fornito nella risposta di Martin Smith diversi anni fa.
jk7

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

7
Ciao Surjeet Singh Bisht; il tuo codice potrebbe essere corretto, ma con un certo contesto darebbe una risposta migliore; ad esempio, potresti spiegare come e perché questa modifica proposta risolverà il problema dell'interrogante, magari includendo un collegamento alla documentazione pertinente. Ciò lo renderebbe più utile per loro e anche più utile per altri lettori del sito che sono alla ricerca di soluzioni a problemi simili.
Vince Bowdren,

5
Questa risposta non aggiunge nulla di nuovo. In realtà questa stessa identica linea fa parte della risposta accettata da oltre 5 anni .
SL Barth - Ripristina Monica il

1
Inoltre, è importante ricordare che l' IIF si applica solo a SQL Server a partire dal 2012
Ivan Rascon,

5

Puoi avere due scelte per implementarlo effettivamente:

  1. Utilizzando IIF, che è stato introdotto da SQL Server 2012:

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

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

4

Domanda:

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'uso degli alias - pin questo caso - aiuterà a prevenire i problemi.


3

L'uso di SQL CASE è proprio come le normali istruzioni If / Else. Nella query seguente, se valore obsoleto = 'N' o se valore InStock = 'Y', l'output sarà 1. Altrimenti l'output sarà 0. Quindi inseriamo quel valore 0 o 1 nella colonna vendibile.

SELECT
      CASE 
        WHEN obsolete = 'N' OR InStock = 'Y' 
        THEN 1 
        ELSE 0 
      END AS Salable
      , * 
FROM PRODUCT

1
Suona bene. Forse una parola o due per spiegarlo?
JQSOFT,

È proprio come le normali dichiarazioni If / Else. Se il valore obsoleto = 'N' o Se il valore InStock = 'Y', l'output sarà 1. In caso contrario, l'output sarà 0.
Tharuka,

1
Grazie. Si prega di modificare il tuo post per aggiungere questa spiegazione. Come: Le If..Then...Else..dichiarazioni utilizzano SQLcome segue ....
JQSOFT,

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

8
Dalla recensione: Benvenuti in Stack Overflow! Per favore, non rispondere solo con il codice sorgente. Prova a fornire una bella descrizione del funzionamento della tua soluzione. Vedi: Come posso scrivere una buona risposta? . Grazie
sɐunıɔ ןɐ qɐp

3
Penso che scoprirai che questo non viene eseguito, perché manca qualsiasi output che segue la parola chiave "THEN".
Dodecaphone,

Puoi elaborare?
Peter Mortensen,

2

Sarà qualcosa del genere:

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;

Possiamo usare il valore QuantityText in cui condizione in una query? per esempioSELECT 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

Per completezza, aggiungerei che SQL utilizza una logica a tre valori. L'espressione:

obsolete = 'N' OR instock = 'Y'

Potrebbe produrre tre risultati distinti:

| 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     |

Quindi, ad esempio, se un prodotto è obsoleto ma non sai se il prodotto è instock, non sai se il prodotto è vendibile. È possibile scrivere questa logica a tre valori come segue:

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

Una volta capito come funziona, puoi convertire tre risultati in due risultati decidendo il comportamento di null. Ad esempio, questo considererebbe null come non vendibile:

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

0

Mi piace l'uso delle istruzioni CASE ma la domanda posta per un'istruzione IF in SQL Select. Quello che ho usato in passato è stato:

SELECT

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

FROM ...

È come le istruzioni IF di Excel o fogli in cui esiste una condizione seguita dalla condizione vera e quindi dalla condizione falsa:

if(condition, true, false)

Inoltre, puoi annidare le istruzioni if ​​(ma quindi usare dovrebbe usare un CASE :-)

(Nota: funziona in MySQLWorkbench ma potrebbe non funzionare in altre piattaforme)


0

È possibile utilizzare l'istruzione case:

Select 
Case WHEN (Obsolete = 'N' or InStock = 'Y') THEN 1 ELSE 0 END Saleable,
Product.*
from Product
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.