Como executo um IF ... THEN em um SQL SELECT?

1508

Como executo IF...THENuma SQL SELECTdeclaração?

Por exemplo:

SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
Eric Labashosky
fonte
14
Você pode dar uma olhada neste link . Em relação às cláusulas: SQL WHERE: Evite CASE, use lógica booleana
Alguém
3
@ Alguém: não é realmente relevante porque o artigo fala sobre o uso de regras de reescrita lógica para converter uma implicação em uma disjunção. A pista é a palavra 'lógico', ou seja, algo que se resolva como verdadeiro ou falso, que não se aplica à projeção. TL; DR artigo aplica-se a WHEREe CHECK, mas não SELECT.
onedaywhen
6
A resposta de @ MartinSmith é a mais elegante - use IIF no SQL 2012+.
Murray Foxcroft

Respostas:

1760

A CASEinstrução é a mais próxima de IF no SQL e é suportada em todas as versões do SQL Server.

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

Você só precisa fazer isso CASTse desejar o resultado como um valor booleano. Se você está satisfeito com um int, isso funciona:

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

CASEinstruções podem ser incorporadas em outras CASEinstruções e até incluídas em agregados.

O SQL Server Denali (SQL Server 2012) adiciona a instrução IIF , que também está disponível no acesso (apontada por Martin Smith ):

SELECT IIF(Obsolete = 'N' or InStock = 'Y', 1, 0) as Saleable, * FROM Product
Darrel Miller
fonte
57
Apenas uma palavra adicional de cautela não inclua suas condições em braquetes ao usar o estojo. Tomou um pouco de tempo para perceber que :)
Archan Mishra
17
e não se esqueça do fim
Simon_Weaver 28/01
8
e o bit AS!
precisa saber é o seguinte
8
Case, When, Else e End devem ser recuados paralelos (na mesma linha) - e somente então devem ser recuados mais para dentro - funciona melhor para mim.
Ujjwal Singh
6
@ReeveStrife Apenas se o SQL Server 2012
superior
327

A declaração de caso é sua amiga nessa situação e assume uma das duas formas:

O caso simples:

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

O caso estendido:

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

Você pode até colocar instruções de caso em uma ordem por cláusula para pedidos realmente sofisticados.

Jonathan
fonte
32
Eu sei que isso é velho, mas eu acho que deve ser notado que você pode adicionar uma AS Col_Nameapós a ENDnomear a coluna resultante
Ben
9
Eu sempre sinto que o segundo é mais simples.
Hogan #
4
Concordo, quase sempre acabo usando a instrução de caso estendida, porque as condições nas quais quero testar são sempre mais complexas do que apenas a única variável. Também me parece mais fácil ler.
Magnum_pi
1
Boa explicação de ambas as situações, com ou sem variável. Com a variável, a condição precisa satisfazer uma igualdade entre a variável após a instrução case e aquela em que você baseia sua condição; sem variável, você pode adicionar uma condição auto-suficiente para testar.
Remus.A
Eu sou mais conveniente com a segunda opção. Os dois estão igualmente bem.
Stanley Okpala Nwosa
277

No SQL Server 2012, você pode usar a IIFfunção para isso.

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

Esta é efetivamente apenas uma maneira abreviada (embora não padrão do SQL) de escrever CASE.

Eu prefiro a concisão quando comparado com a CASEversão expandida .

Ambos IIF()e CASEresolvem como expressões em uma instrução SQL e só podem ser usados ​​em locais bem definidos.

A expressão CASE não pode ser usada para controlar o fluxo de execução de instruções Transact-SQL, blocos de instruções, funções definidas pelo usuário e procedimentos armazenados.

Se suas necessidades não puderem ser atendidas por essas limitações (por exemplo, uma necessidade de retornar conjuntos de resultados de formas diferentes, dependendo de alguma condição), o SQL Server também terá uma IFpalavra-chave de procedimento .

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

Às vezes, deve-se tomar cuidado para evitar problemas de detecção de parâmetros com essa abordagem .

Martin Smith
fonte
6
Essa deve ser a resposta se você deseja uma instrução IF .. then no SQL.
Mr.J
91

Você pode encontrar alguns bons exemplos em Instruções do Power of SQL CASE , e acho que a instrução que você pode usar será algo assim (de 4guysfromrolla ):

SELECT
    FirstName, LastName,
    Salary, DOB,
    CASE Gender
        WHEN 'M' THEN 'Male'
        WHEN 'F' THEN 'Female'
    END
FROM Employees
sven
fonte
4
consulte: meta.stackexchange.com/questions/103053/… para uma discussão interessante. Os dois links que você fornece adicionam contexto extra, o que eu apoio.
Sam Saffron
2
O referem-se é realmente útil e altamente recomendado em caso de detalhes adicionais
baymax
75

Use CASE. Algo assim.

SELECT Salable =
        CASE Obsolete
        WHEN 'N' THEN 1
        ELSE 0
    END
cavalo pálido
fonte
50
SELECT  
(CASE 
     WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
                                            ELSE 'NO' 
 END) as Salable
, * 
FROM Product
John Sheehan
fonte
48

Microsoft SQL Server (T-SQL)

Em a select, use:

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

Em uma wherecláusula, use:

where 1 = case when Obsolete = 'N' or InStock = 'Y' then 1 else 0 end
user7658
fonte
1
por que você não apenas fazer where Obsolete = 'N' or InStock = 'Y'e cortar o onde ao meio praticamente
Maksymiuk
46

Desde esta ligação , podemos compreender IF THEN ELSEem 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' 

Isso não é bom o suficiente para o T-SQL?

Ken
fonte
3
Não é isso que o solicitante queria, mas é muito útil saber que você pode usar instruções if fora de uma instrução select.
Jonathan
2
EXISTS é bom porque sai do loop de pesquisa se o item for encontrado. Uma COUNT é executada até o final das linhas da tabela. Nada a ver com pergunta, mas algo a saber.
JustJohn
45
 SELECT
   CASE 
      WHEN OBSOLETE = 'N' or InStock = 'Y' THEN 'TRUE' 
      ELSE 'FALSE' 
   END AS Salable,
   * 
FROM PRODUCT
Santiago Cepas
fonte
32

Instrução if-else simples no SQL Server:

DECLARE @val INT;
SET @val = 15;

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

GO

Instrução If ... else aninhada no 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
fonte
2
Tarde, mas é utilizável dentro SELECTcomo OP pediu?
abdul qayyum 17/02/19
25

Um novo recurso, IIF (que podemos simplesmente usar), foi adicionado no SQL Server 2012:

SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
sandeep rawat
fonte
1
Essa resposta repete (com menos detalhes) o que foi fornecido na resposta por Martin Smith há vários anos.
Jk7 31/07/19
1
@ jk7 esta foi a primeira resposta para a pergunta.
Sandeep rawat
3
Não pelo que vejo. Ele diz que sua resposta foi publicada em 26 de abril de 16 e Martin foi publicada em 20 de julho de 11.
Jk7 #
24

Use uma instrução CASE:

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

etc...
Krizzy
fonte
23

Use lógica de bits 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

Veja a demonstração de trabalho: se não houver caseno SQL Server .

Para começar, você precisa calcular o valor truee falsepara as condições selecionadas. Aí vem dois NULLIF :

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

combinados fornece 1 ou 0. Em seguida, use operadores bit a bit .

É o método mais WYSIWYG .

Tomasito
fonte
19
-1 para Ofuscação de Código. Sério, isso é o mais longe possível do WYSIWYG! Uma confusão ilegível corado, e se eu tivesse que trabalhar em seu código, eu estaria xingando durante todo o dia ... Desculpe: - /
Heliac
2
@Heliac colocou a parte cte no View e você nunca verá a bagunça. Por muito tempo e complicado AND, OR, NOT, é mais legível que CASE (essa parte fora do cte, é claro).
23913 Tomasito
1
Eu dei +1 a ele pela limpeza, uma vez que está em um cte, mas observe que a resposta está errada para a pergunta. Você precisa de um '|' não é um '&'.
Mark Hurd
3
Concordo totalmente com @Heliac. Embora esteja sintaticamente correto e funcione bem, simplesmente não é facilmente suportável. Colocá-lo em um CTE apenas moverá esse pedaço de código não legível para outro lugar.
objectNotFound
1
O método da tabela de verificação da combinação pode ter suas vantagens. Usar uma variável de tabela e associá-la à consulta existente pode fornecer uma solução baseada em conjunto sem um caso. Essa resposta é um péssimo exemplo, mas a própria ideia da tabela tem mérito.
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' )
um dia quando
fonte
17
SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END as newref
From profile
atik sarker
fonte
Você pode elaborar?
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
fonte
2
Você poderia, por favor, explicar como isso responde à pergunta?
Guanxi
@Guanxi: embora não a minha resposta, um 'case' generaliza um 'if-then-else' (a partir de 2 casos para muitos)
JosephDoggie
Você pode elaborar?
Peter Mortensen
13

Esta não é uma resposta, apenas um exemplo de uma declaração CASE em uso onde eu trabalho. Ele possui uma instrução CASE aninhada. Agora você sabe por que meus olhos estão cruzados.

 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
fonte
1
A edição que reformatou as instruções Case é ótima e elegante e a torna mais compreensível, mas o SQL ainda se aglomera na exibição que está sendo usada.
JustJohn
1
Estou apenas vagando por que CASEser votado e marcado como uma resposta em vez da IFque deveria ter sido a resposta, como esta, essa ainda é uma CASEafirmação, não uma IF.
Mr.J
@ Mr.J: embora não a minha resposta, um 'case' generaliza um 'if-then-else' (a partir de 2 casos para muitos)
JosephDoggie
12

Se você estiver inserindo resultados em uma tabela pela primeira vez, em vez de transferir resultados de uma tabela para outra, isso funcionará no 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
fonte
4
as tags dizem SQL Server, TSQL
Malachi
11

Como uma solução alternativa à CASEinstrução, uma abordagem orientada a tabela pode ser usada:

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

Resultado:

ID          Obsolete   InStock    Saleable
----------- ---------- ---------- -----------
1           N          Y          1
2           A          B          0
3           N          B          1
4           A          Y          1
Serkan Arslan
fonte
O vendável é usado em que condição na consulta?
Bhavin Thummar 08/11/19
Pode ser usado em condições onde.
precisa saber é o seguinte
9
SELECT CASE WHEN Obsolete = 'N' or InStock = 'Y' THEN 1 ELSE 0 
             END AS Saleable, * 
FROM Product

fonte
6

Para quem usa o SQL Server 2012, o IIF é um recurso que foi adicionado e funciona como uma alternativa às instruções Case.

SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM   Product 
Dibin
fonte
1
Essa resposta repete (com menos detalhes) o que foi fornecido na resposta por Martin Smith há vários anos.
Jk7 31/07/19
6
  SELECT IIF(Obsolete = 'N' OR InStock = 'Y',1,0) AS Saleable, * FROM Product
SURJEET SINGH Bisht
fonte
7
Olá Surjeet Singh Bisht; seu código pode estar correto, mas com algum contexto, seria uma resposta melhor; por exemplo, você pode explicar como e por que essa alteração proposta resolveria o problema do questionador, talvez incluindo um link para a documentação relevante. Isso tornaria mais útil para eles e também para outros leitores de sites que estão procurando soluções para problemas semelhantes.
Vince Bowdren
5
Esta resposta não adiciona nada de novo. De fato, essa mesma linha faz parte da resposta aceita há mais de 5 anos .
SL Barth - Restabelece Monica 30/11
1
Além disso, é importante mencionar que o IIF se aplica apenas ao SQL Server a partir de 2012
Ivan Rascon
5

Você pode ter duas opções para isso realmente implementar:

  1. Usando o IIF, que foi introduzido no SQL Server 2012:

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

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

Questão:

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;

Usar aliases - pneste caso - ajudará a evitar problemas.

David Cohn
fonte
3

O uso do SQL CASE é como as instruções If / Else normais. Na consulta abaixo, se o valor obsoleto = 'N' ou o valor InStock = 'Y', a saída será 1. Caso contrário, a saída será 0. Em seguida, colocamos esse valor 0 ou 1 na coluna Salable.

SELECT
      CASE 
        WHEN obsolete = 'N' OR InStock = 'Y' 
        THEN 1 
        ELSE 0 
      END AS Salable
      , * 
FROM PRODUCT
Tharuka
fonte
1
Parece bom. Talvez uma palavra ou duas para explicar?
JQSOFT
É como as declarações If / Else normais. Se o valor obsoleto = 'N' ou o valor InStock = 'Y', a saída será 1. Caso contrário, a saída será 0.
Tharuka
1
Obrigado. Por favor Edite seu post para adicionar essa explicação. Como: O If..Then...Else..uso de instruções da SQLseguinte maneira ....
JQSOFT 18/02
2
SELECT 
  CAST(
    CASE WHEN Obsolete = 'N' 
    or InStock = 'Y' THEN ELSE 0 END AS bit
  ) as Saleable, * 
FROM 
  Product
gii96
fonte
8
Da avaliação: Bem-vindo ao Stack Overflow! Por favor, não responda apenas com o código fonte. Tente fornecer uma boa descrição sobre como sua solução funciona. Veja: Como escrevo uma boa resposta? . Obrigado
sɐunıɔ ןɐ qɐp
3
Eu acho que você encontrará que isso não é executado, porque está faltando alguma saída após a palavra-chave 'THEN'.
Dodecaphone
Você pode elaborar?
Peter Mortensen
2

Será algo assim:

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
fonte
Podemos usar o valor QuantityText na condição where em uma consulta? por exemploSELECT 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 8/11/19
1

Por uma questão de integridade, eu acrescentaria que o SQL usa lógica de três valores. A expressão:

obsolete = 'N' OR instock = 'Y'

Pode produzir três resultados distintos:

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

Por exemplo, se um produto é obsoleto, mas você não sabe se o produto é instock, você não sabe se o produto é vendável. Você pode escrever essa lógica de três valores da seguinte maneira:

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

Depois de descobrir como ele funciona, você pode converter três resultados em dois, decidindo o comportamento de nulo. Por exemplo, isso trataria null como não vendável:

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

Eu gosto do uso das instruções CASE, mas a pergunta solicitou uma instrução IF no SQL Select. O que eu usei no passado foi:

SELECT

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

FROM ...

É como as instruções IF do excel ou de folhas em que há um condicional seguido pela condição verdadeira e depois pela condição falsa:

if(condition, true, false)

Além disso, você pode aninhar as instruções if (mas, em seguida, use deve usar um CASE :-)

(Nota: isso funciona no MySQLWorkbench, mas pode não funcionar em outras plataformas)

Prashant Marathay
fonte
0

Você pode usar a declaração de caso:

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