¿La declaración CASE de SQL Server evalúa todas las condiciones o sale en la primera condición VERDADERA?

44

¿La CASEdeclaración de SQL Server (2008 o 2012, específicamente) evalúa todas las WHENcondiciones o se cierra una vez que encuentra una WHENcláusula que se evalúa como verdadera? Si pasa por todo el conjunto de condiciones, ¿eso significa que la última condición que se evalúa como verdadera sobrescribe lo que hizo la primera condición que se evaluó como verdadera? Por ejemplo:

SELECT
    CASE
        WHEN 1+1 = 2 THEN'YES'
        WHEN 1+1 = 3 THEN 'NO'
        WHEN 1+1 = 2 THEN 'NO' 
    END

El resultado es "SÍ" aunque sea el último momento en que la condición debería hacer que se evalúe como "NO". Parece que sale una vez que encuentra la primera condición VERDADERA. ¿Alguien puede confirmar si este es el caso ?

Juan velez
fuente
55
Muy relacionado: ¿SQL Server lee toda una función COALESCE incluso si el primer argumento no es NULL? (como COALESCE()se traduce en una CASEexpresión.)
ypercubeᵀᴹ

Respuestas:

46

• Devuelve el resultado_expresión de la primera input_expression = when_expression que se evalúa como TRUE .

Referencia http://msdn.microsoft.com/en-us/library/ms181765.aspx


Este es el comportamiento estándar de SQL:

  • Una CASEexpresión se evalúa como la primera condición verdadera.

  • Si no hay una condición verdadera, se evalúa en la ELSEparte.

  • Si no hay una condición verdadera y ninguna ELSEparte, se evalúa como NULL.

James Jenkins
fuente
2
Solo quería asegurarme de que si tengo 3 condiciones de caso que se evaluarían como verdaderas, solo querría que se ejecutara la tarea de la primera que se evalúa como verdadera y no las otras 2 (aunque también se evaluaron como verdaderas) ) De la consulta de ejemplo en mis preguntas, este parece ser el caso. Solo quería confirmar. También esperaba que SQL lea las condiciones CASE de arriba a abajo. ¡Gracias!
Juan Velez
15

SQL Server generalmente realiza una evaluación de cortocircuito para sentencias CASE ( SQLFiddle ):

--Does not fail on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 1 THEN 'Case 1'
      WHEN 2/0 = 1 THEN 'Case 2'
   END;

--Fails on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 99 THEN 'Case 1'
      WHEN 2/0 = 99 THEN 'Case 2'
   END;  

Sin embargo, hay varios tipos de declaraciones que a partir de SQL Server 2012 no provocan un cortocircuito correctamente. Ver el enlace de ypercube en los comentarios.

Oracle siempre realiza evaluaciones de cortocircuitos . Consulte la referencia del lenguaje SQL 11.2 . O compare lo siguiente ( SQLFiddle ):

--Does not fail on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 1 THEN 'Case 1'
    WHEN 2/0 = 1 THEN 'Case 2'
  END
FROM dual;


--Fails on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 99 THEN 'Case 1'
    WHEN 2/0 = 99 THEN 'Case 2'
  END
FROM dual;

Esta misma prueba no se puede hacer con MySQL porque devuelve NULL para la división por cero. ( SQL Fiddle )

Leigh Riffel
fuente
¿Qué tal esto ?: SQL-Fiddle
ypercubeᵀᴹ
1
El violín es sobre SQL-Server . Es la respuesta de Aaron aquí: ¿SQL Server lee toda una función COALESCE incluso si el primer argumento no es NULL?
ypercubeᵀᴹ
@ypercube Ese es un comportamiento realmente interesante. Está evaluando el código que se ejecutaría en la parte else, pero parece ignorarlo dependiendo de qué otras expresiones WHEN existen y si la división por cero está dentro de un MIN o no. Ver sqlfiddle.com/#!6/d41d8/4468
Leigh Riffel
@ypercube Ahora que he leído algunos de los enlaces que publicaste, ¿dirías que hay suficientes casos extremos para decir que la respuesta a si SQL Server realiza una evaluación de cortocircuito es, por lo general?
Leigh Riffel
3
Sí, estaría de acuerdo en "generalmente". Como Aaron señala su respuesta, una prueba es suficiente para refutar el "CASO siempre cortocircuitos". Pero generalmente lo hace.
ypercubeᵀᴹ
7

Parece que MS SQL Server también usa una evaluación de cortocircuito.

En la siguiente prueba tengo 3 pruebas. El primero siempre es cierto, el segundo falla sin hacer referencia a la tabla y el tercero falla solo cuando se tienen en cuenta los datos.
En esta ejecución particular, ambas filas se devuelven correctamente. Si comento el primer CUÁNDO, o el primero y el segundo, obtengo fallas.

CREATE TABLE casetest (test varchar(10))
GO
INSERT INTO casetest VALUES ('12345'),('abcdef')
GO

SELECT CASE WHEN LEN(test)>1 THEN test
        WHEN 1/0 = 1 THEN 'abc'
        WHEN CAST(test AS int) = 1 THEN 'def'
        END
FROM casetest
GO
Kenneth Fisher
fuente
1

si la declaración de caso utilizada en la WHEREcondición y el primer caso cuando la declaración involucra la evaluación de los valores de columna de la tabla, y la primera fila de la tabla no satisface esta condición, la declaración del caso pasará al siguiente caso cuando la declaración.

declare @tbl table(id int)
insert into @tbl values(1)
insert into @tbl values(2)
insert into @tbl values(3)

--Fails on the divide by zero.
SELECT * FROM @tbl
where  CASE 
        WHEN id = 2 THEN 1 -- first row in table will not satisfy the condition
        WHEN 2/0 = 1 THEN 1
        ELSE 0
      END =1

-- when filter the records to only who will staisfy the first case when condition, it 
will not fail on the divide by zero
SELECT * FROM @tbl
where ID=2 and -- first row in table will  satisfy the condition
  CASE 
    WHEN id = 2 THEN 1
    WHEN 2/0 = 1 THEN 1
    ELSE 0
  END =1
abdelmoniem hafez
fuente
1

En MySQL saldrá de la declaración de caso en la primera opción verdadera. Si tiene la posibilidad de múltiples valores verdaderos, desea colocar la respuesta preferida anteriormente en la secuencia.

Robar
fuente
La pregunta es sobre SQL Server.
James Anderson