¿Cómo realizo un IF ... THEN en un SQL SELECT?

¿Cómo realizo un IF ... THEN en un SQL SELECT?

¿Cómo realizo un IF...THEN en una declaración SQL SELECT ?

Por ejemplo:

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

Es posible que desee ver este enlace . Con respecto a: Cláusulas WHERE de SQL: Evite CASE, use lógica booleana

@Somebody: no es realmente relevante porque el artículo habla sobre el uso de reglas lógicas de reescritura para convertir una implicación en una disyunción. La pista es la palabra 'lógico', es decir, algo que se resuelve en verdadero o falso, que no se aplica a la proyección. El artículo TL; DR se aplica a WHERE y CHECK pero no a SELECT .

La respuesta de @ MartinSmith es la más elegante: use IIF en SQL 2012+.

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

Use CASE. Algo como esto.

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

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

La instrucción CASE es la más cercana a IF en SQL y es compatible con todas las versiones de SQL Server.

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

Solo necesita hacer el CAST si desea que el resultado sea un valor booleano. Si está satisfecho con un int , esto funciona:

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

CASE se pueden incrustar en otras declaraciones CASE e incluso incluirse en agregados.

SQL Server Denali (SQL Server 2012) agrega el Declaración IIF que también está disponible en acceso ( señalado por Martin Smith ):

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

Solo una advertencia adicional no incluya sus condiciones entre paréntesis cuando use el estuche. Tomó bastante tiempo darse cuenta de eso :)

y no olvides el FIN

y el bit AS!

Caso, cuándo, Else y End deben tener sangría paralela (a lo largo de la misma línea), y solo entonces deben sangrarse más hacia adentro, funciona mejor para mí.

Avatar JMD

Necesitaba CASOS anidados y olvidaba que necesitaba múltiples END coincidentes.

Aunque esto funciona, usar la función IFF () será la mejor respuesta

@ReeveStrife Te refieres a IIF() msdn.microsoft.com/en-us/library/…

@ReeveStrife solo si SQL Server 2012+

@ArchanMishra Hola Archan, ¿podría explicarme por qué no debe incluir sus condiciones?

Tenga cuidado con los secretos sucios de CASE / IIF: sqlperformance.com/2014/06/t-sql-queries/…

@ArchanMishra puedes. Pensé que quería decir que reduciría las cosas, pero no. Puede usar corchetes tantas veces como desee en SQL Server, siempre que tenga sentido lógico para SQL.

@DarrelMiller probablemente pueda devolver VERDADERO o FALSO en la declaración CASE y evitar CAST, no estoy seguro de si funciona en SQL Server, pero creo que es SQL. Nunca he visto algo así

Puede encontrar algunos buenos ejemplos en El poder de las declaraciones CASE de SQL , y creo que la declaración que puede usar será algo como esto (de 4guysfromrolla ):

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

ver: meta.stackexchange.com/questions/103053/… para una discusión interesante. Los dos enlaces que proporciona agregan un contexto adicional, que yo apoyo.

La referencia es realmente útil y muy recomendable en caso de detalles adicionales.

Microsoft SQL Server (T-SQL)

En un select , use:

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

En una cláusula where , use:

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

¿por qué no harías where Obsolete = 'N' or InStock = 'Y' y cortarías el where por la mitad prácticamente

Use una declaración CASE:

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

etc...
 

La declaración del caso es su amigo en esta situación, y toma una de dos formas:

El caso simple:

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

El caso extendido:

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

Incluso puede poner declaraciones de caso en un orden por cláusula para un pedido realmente elegante.

Avatar Ben

Sé que esto es antiguo, pero creo que debe tenerse en cuenta que puede agregar un AS Col_Name después del END para nombrar la columna resultante

Siempre siento que el segundo es más simple.

De acuerdo, casi siempre termino usando el enunciado de caso extendido porque las condiciones en las que quiero probar son siempre más complejas que solo la variable en sí. También me parece más fácil de leer.

Buena explicación de ambas situaciones, con o sin variable. Con la variable, la condición debe satisfacer una igualdad entre la variable después de la declaración del caso y la base en la que basa su condición, sin la variable puede agregar una condición autosuficiente para probar.

Soy más conveniente con la segunda opción. Los dos están igualmente bien.

Avatar Ken

De este enlace , podemos entender IF THEN ELSE en 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' 
 

¿No es esto lo suficientemente bueno para T-SQL?

Esto no es lo que el solicitante quería, pero es muy útil saber que puede usar si las declaraciones fuera son una declaración de selección.

EXISTS es bueno porque se elimina del ciclo de búsqueda si se encuentra un elemento. COUNT se ejecuta hasta el final de las filas de la tabla. Nada que ver con preguntas, sino algo que saber.

Desde SQL Server 2012 puede usar el IIF función para esto.

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

Esto es efectivamente una forma abreviada (aunque no estándar de SQL) de escribir CASE .

Prefiero la concisión en comparación con la versión expandida de CASE .

Tanto IIF() como CASE se resuelven como expresiones dentro de una declaración SQL y solo se pueden usar en lugares bien definidos.

  

La expresión CASE no se puede usar para controlar el flujo de ejecución de   Sentencias Transact-SQL, bloques de sentencias, funciones definidas por el usuario y   procedimientos almacenados.

Si sus necesidades no pueden satisfacerse con estas limitaciones (por ejemplo, la necesidad de devolver conjuntos de resultados con formas diferentes que dependen de alguna condición), entonces SQL Server también tiene un procedimiento IF palabra clave.

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

Sin embargo, a veces se debe tener cuidado para evitar problemas de detección de parámetros con este enfoque .

Esta debería ser la respuesta si desea un IF ... luego una declaración en SQL.

Si está insertando resultados en una tabla por primera vez, en lugar de transferir resultados de una tabla a otra, esto funciona en 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');
 

las etiquetas dicen SQL Server, TSQL

Usar lógica de bit puro:

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
 

Consulte demostración de trabajo: si es así sin case en SQL Server .

Para comenzar, necesita calcular el valor de true y false para las condiciones seleccionadas. Aquí vienen dos NULLIF :

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

combinados juntos da 1 o 0. Siguiente uso operadores bit a bit .

Es el método más WYSIWYG .

-1 para el Código de Ofuscación. En serio, ¡esto está tan lejos de WYSIWYG como puedas! Un desorden rojizo e ilegible, y si tuviera que trabajar en su código, estaría maldiciendo todo el día ... lo siento: - /

@Heliac puso cte part en View y nunca verás el desorden. Para largos y complicados AND, OR, NO es más legible que CASE (esa parte fuera de cte, por supuesto).

Le di a esto un +1 para la limpieza, una vez que está en un cte, pero tenga en cuenta que la respuesta actualmente es incorrecta para la pregunta. Necesitas un '|' no un '&'.

Totalmente de acuerdo con @Heliac. Si bien es sintácticamente correcto y funciona bien, simplemente no es fácilmente compatible. Ponerlo en un CTE solo moverá ese fragmento de código no legible a otro lugar.

El método de tabla para verificar la combinación podría tener sus ventajas. Usar una variable de tabla y unirla a la consulta existente podría proporcionar una solución basada en conjuntos sin un caso. Esta respuesta es un mal ejemplo, pero la idea de la tabla en sí misma tiene mérito.

El enlace NULLIF de Microsoft ha caducado. Aquí hay un nuevo enlace de trabajo: docs.microsoft.com/en-us/sql/t-sql/language-elements/… Actualizado en respuesta.

Para aquellos que usan SQL Server 2012, IIF es una característica que se ha agregado y funciona como una alternativa a las declaraciones de casos.

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

Avatar jk7

Esta respuesta repite (con menos detalles) lo que fue ya proporcionado en la respuesta de Martin Smith hace varios años.

SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END as newref
From profile
 

¿Puedes elaborar?

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
 

¿Podría explicarme cómo responde esto a la pregunta?

@Guanxi: aunque no es mi respuesta, un 'caso' generaliza un 'si-entonces-otro' (de 2 casos a muchos)

¿Puedes elaborar?

Declaración simple if-else en SQL Server:

DECLARE @val INT;
SET @val = 15;

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

GO
 

Sentencia anidada If ... else en 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
 

Tarde, pero ¿se puede usar dentro de SELECT como OP preguntó?

Esta no es una respuesta, solo un ejemplo de una declaración CASE en uso donde trabajo. Tiene una declaración CASE anidada. Ahora sabes por qué mis ojos están 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]
 

La edición que volvió a formatear las declaraciones de Case está bien y es elegante y lo hace más comprensible, pero el SQL aún se acumularía en la vista que lo está usando.

Solo me pregunto por qué CASE se votó a favor y se marcó como respuesta en lugar de IF , que debería haber sido la respuesta, como esta, esta sigue siendo un CASE , no un IF .

@ Mr.J: aunque no es mi respuesta, un 'caso' generaliza un 'si-entonces-otro' (de 2 casos a muchos)

Una nueva función, IIF (que simplemente podemos usar) , se agregó en SQL Server 2012:

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

Avatar jk7

Esta respuesta repite (con menos detalles) lo que fue ya proporcionado en la respuesta de Martin Smith hace varios años.

@ jk7 esta fue la primera respuesta a la pregunta.

Avatar jk7

No por lo que veo. Dice que su respuesta se publicó el 26 de abril de 16 y la de Martin se publicó el 20 de julio de 11.

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

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

Hola surjeet singh bisht; su código puede ser correcto, pero con algún contexto sería una mejor respuesta; por ejemplo, podría explicar cómo y por qué este cambio propuesto resolvería el problema del interlocutor, tal vez incluyendo un enlace a la documentación relevante. Eso lo haría más útil para ellos, y también más útil para otros lectores del sitio que buscan soluciones a problemas similares.

Esta respuesta no agrega nada nuevo. De hecho, esta misma línea ha sido parte de la respuesta aceptada durante más de 5 años .

Además es importante mencionar que el IIF solo se aplica a SQL Server a partir de 2012

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

Como una solución alternativa a la declaración CASE , se puede utilizar un enfoque basado en tablas:

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
 

¿Se puede vender en condiciones de consulta?

Se puede usar en donde condición.

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

De la opinión: Bienvenido a Stack Overflow! Por favor no responda solo con el código fuente. Intente proporcionar una buena descripción sobre cómo funciona su solución. Consulte: ¿Cómo escribo una buena respuesta? . Gracias

Creo que encontrará que esto no se ejecuta, ya que le falta algún resultado después de la palabra clave 'ENTONCES'.

¿Puedes elaborar?

Pregunta:

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;
 

El uso de alias - p en este caso - ayudará a prevenir problemas.

Puede tener dos opciones para implementar esto realmente:

  1. Usando IIF, que se introdujo desde SQL Server 2012:

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

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

Será algo así:

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;
 

¿Podemos usar el valor de CantidadTexto en donde condición en una consulta? por ejemplo 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 WHERE QuantityText = 'The quantity is 30';

En aras de la exhaustividad, agregaría que SQL utiliza lógica de tres valores. La expresión:

obsolete = 'N' OR instock = 'Y'
 

Podría producir tres 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     |
  

Entonces, por ejemplo, si un producto es obsoleto pero no sabe si el producto es instock, entonces no sabe si el producto es vendible. Puede escribir esta lógica de tres valores de la siguiente manera:

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 vez que descubra cómo funciona, puede convertir tres resultados en dos resultados al decidir el comportamiento de nulo. P.ej. esto trataría nulo como no vendible:

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