L'istruzione CASE di SQL Server valuta tutte le condizioni o esce alla prima condizione VERA?


44

L'istruzione SQL Server (2008 o 2012, in particolare) CASEvaluta tutte le WHENcondizioni o esce una volta trovata una WHENclausola che restituisce true? Se attraversa l'intero insieme di condizioni, ciò significa che l'ultima condizione che valuta su vero sovrascrive ciò che ha fatto la prima condizione che ha valutato vero? Per esempio:

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

Il risultato è "SÌ" anche se l'ultima condizione in cui dovrebbe essere valutata su "NO". Sembra che esca quando trova la prima VERA condizione. Qualcuno può confermare se questo è il caso .


5
Molto strettamente correlato: SQL Server legge tutte le funzioni COALESCE anche se il primo argomento non è NULL? (come COALESCE()tradotto in CASEun'espressione.)
ypercubeᵀᴹ

Risposte:


46

• Restituisce il risultato_espressione del primo input_expression = when_expression che restituisce TRUE .

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


Questo è un comportamento SQL standard:

  • CASEUn'espressione restituisce alla prima condizione vera.

  • Se non esiste una condizione vera, viene valutata la ELSEparte.

  • Se non esiste una condizione vera e nessuna ELSEparte, viene valutata NULL.


2
Volevo solo assicurarmi che se avessi 3 condizioni di caso che valuterebbero tutte true, vorrei solo che il compito del primo che valuta true fosse eseguito e non l'altro 2 (anche se hanno anche valutato true ). Dalla query di esempio nelle mie domande questo sembra essere il caso. Volevo solo confermare. Speravo anche che SQL leggesse le condizioni CASE dall'alto verso il basso. Grazie!
Juan Velez,

15

SQL Server di solito esegue una valutazione di corto circuito per le istruzioni 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;  

Esistono tuttavia diversi tipi di istruzioni che a partire da SQL Server 2012 non eseguono correttamente il corto circuito. Vedi il link da ypercube nei commenti.

Oracle esegue sempre una valutazione di corto circuito . Vedi 11.2 Riferimento al linguaggio SQL . Oppure confronta il seguente ( 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;

Questo stesso test non può essere eseguito con MySQL perché restituisce NULL per divisione per zero. ( SQL Fiddle )


Che ne dici di questo ?: SQL-Fiddle
ypercubeᵀᴹ

1
Il violino riguarda SQL Server . È la risposta di Aaron qui: SQL Server legge tutte le funzioni COALESCE anche se il primo argomento non è NULL?
ypercubeᵀᴹ

@ypercube Questo è un comportamento davvero interessante. Sta valutando il codice che verrebbe eseguito nella parte else, ma sembra ignorarlo a seconda di quali altre espressioni WHEN esistono e se la divisione per zero è all'interno di un MIN o meno. Vedi sqlfiddle.com/#!6/d41d8/4468
Leigh Riffel,

@ypercube Ora che ho letto alcuni dei link che hai pubblicato, diresti che ci sono abbastanza casi limite per dire che la risposta al fatto che SQL Server esegua la valutazione del corto circuito è - di solito?
Leigh Riffel,

3
Sì, sono d'accordo su "di solito". Mentre Aaron indica la sua risposta, un test è sufficiente per confutare il "CASO sempre in cortocircuito". Ma di solito lo fa.
ypercubeᵀᴹ

7

Sembra che MS SQL Server utilizzi anche una valutazione di corto circuito.

Nel seguente test ho 3 test. Il primo è sempre vero, il secondo fallisce senza fare riferimento alla tabella e il terzo fallisce solo quando si prendono in considerazione i dati.
In questa particolare esecuzione entrambe le righe vengono restituite correttamente. Se commento il primo QUANDO, o il primo e il secondo, ottengo degli errori.

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 l'istruzione case utilizzata nella WHEREcondizione e il primo caso in cui l'istruzione comportano la valutazione dei valori di colonna dalla tabella e la prima riga della tabella non soddisfa questa condizione, l'istruzione case passerà al caso successivo all'istruzione.

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

In MySQL uscirà l'istruzione case sulla prima vera opzione. Se hai la possibilità di più valori veri, vuoi inserire la risposta preferita prima nella sequenza.


La domanda riguarda SQL Server.
James Anderson,
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.