A instrução CASE do SQL Server avalia todas as condições ou sai na primeira condição TRUE?


44

A instrução do SQL Server (2008 ou 2012, especificamente) CASEavalia todas as WHENcondições ou sai quando encontra uma WHENcláusula avaliada como verdadeira? Se ele passar por todo o conjunto de condições, isso significa que a última condição avaliada como verdadeira substitui o que a primeira condição avaliada como verdadeira fez? Por exemplo:

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

O resultado é "SIM", mesmo sendo a última condição em que deve avaliar como "NÃO". Parece que sai depois de encontrar a primeira condição VERDADEIRA. Alguém pode confirmar se é esse o caso .


5
Muito relacionado: O SQL Server lê toda uma função COALESCE, mesmo que o primeiro argumento não seja NULL? (como COALESCE()é traduzida para uma CASEexpressão.)
ypercubeᵀᴹ

Respostas:


46

• Retorna a expressão result_ da primeira expressão input_ = when_expression que é avaliada como TRUE .

Referência http://msdn.microsoft.com/en-us/library/ms181765.aspx


Este é o comportamento padrão do SQL:

  • Uma CASEexpressão é avaliada para a primeira condição verdadeira.

  • Se não houver uma condição verdadeira, ela avalia a ELSEpeça.

  • Se não houver uma condição verdadeira e nenhuma ELSEparte, ela será avaliada como NULL.


2
Eu só queria ter certeza de que, se eu tivesse três condições de caso que seriam avaliadas como verdadeiras, eu apenas desejaria que a tarefa da primeira que fosse avaliada como verdadeira fosse executada e não as outras 2 (mesmo que elas também tenham sido avaliadas como verdadeiras). ) A partir da consulta de exemplo em minhas perguntas, esse parece ser o caso. Eu só queria confirmar. Eu também esperava que o SQL leia as condições CASE de cima para baixo. Obrigado!
Juan Velez

15

O SQL Server geralmente faz uma avaliação de curto-circuito para instruções 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;  

No entanto, existem vários tipos de instruções que, no SQL Server 2012, não causam um curto-circuito correto. Veja o link do ypercube nos comentários.

A Oracle sempre faz avaliação de curto-circuito . Consulte a Referência da linguagem SQL 11.2 . Ou compare o seguinte ( 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;

Este mesmo teste não pode ser feito com o MySQL porque retorna NULL para divisão por zero. ( SQL Fiddle )


Como sobre isto ?: SQL-Fiddle
ypercubeᵀᴹ


@ypercube Esse é um comportamento realmente interessante. Ele está avaliando o código que seria executado na parte else, mas parece ignorá-lo, dependendo de quais outras expressões WHEN existirem e se a divisão por zero está dentro de um MIN ou não. Veja sqlfiddle.com/#!6/d41d8/4468
Leigh Riffel

@ypercube Agora que eu li alguns dos links que você postou, você diria que existem casos extremos suficientes para dizer que a resposta para se o SQL Server faz uma avaliação de curto-circuito é - normalmente?
Leigh Riffel

3
Sim, eu concordo com "normalmente". Como Aaron aponta em sua resposta, um teste é suficiente para refutar o "CASO sempre curto-circuito". Mas geralmente faz.
ypercubeᵀᴹ

7

Parece que o MS SQL Server também usa uma avaliação de curto-circuito.

No teste a seguir, tenho 3 testes. O primeiro é sempre verdadeiro, o segundo falha sem fazer referência à tabela e o terceiro falha apenas quando os dados são levados em consideração.
Nesta execução específica, as duas linhas são retornadas com sucesso. Se eu comentar o primeiro WHEN, ou o primeiro e o segundo, recebo falhas.

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

1

se a instrução de caso usada na WHEREcondição e o primeiro caso quando envolver envolver a avaliação de valores de coluna da tabela e a primeira linha da tabela não atender a essa condição, a instrução de caso passará para o caso seguinte quando instrução.

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

1

No MySQL, ele sairá da instrução case na primeira opção verdadeira. Se você tem a possibilidade de vários valores verdadeiros, deseja colocar a resposta preferida anteriormente na sequência.


A questão é sobre o SQL Server.
James Anderson
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.