Czy instrukcja CASE programu SQL Server ocenia wszystkie warunki lub wychodzi z pierwszego warunku PRAWDA?

44

Czy instrukcja SQL Server (w szczególności 2008 lub 2012) CASEocenia wszystkie WHENwarunki, czy też wychodzi, gdy znajdzie WHENklauzulę, która ma wartość true? Jeśli przejdzie przez cały zestaw warunków, czy to oznacza, że ​​ostatni warunek oceniający na prawda zastępuje to, co zrobił pierwszy warunek, który oceniono na prawda? Na przykład:

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

Wynikiem jest „TAK”, chociaż ostatni warunek, w którym warunek powinien dać wynik „NIE”. Wygląda na to, że kończy działanie, gdy znajdzie pierwszy PRAWDZIWY warunek. Może ktoś proszę potwierdzić, czy jest to przypadek .

Juan Velez
źródło
5
Bardzo ściśle powiązane: Czy SQL Server odczytuje wszystkie funkcje COALESCE, nawet jeśli pierwszy argument nie ma wartości NULL? (jak COALESCE()to tłumaczy się na CASEwyrażenie).
ypercubeᵀᴹ

Odpowiedzi:

46

• Zwraca wynik_wyrażenia pierwszego wyrażenia_wejściowego = wyrażenie_czasu, którego wynikiem jest PRAWDA .

Odwołanie http://msdn.microsoft.com/en-us/library/ms181765.aspx


To jest standardowe zachowanie SQL:

  • CASEWyrażenie do pierwszego prawdziwego stanu.

  • Jeśli nie ma żadnego prawdziwego warunku, ocenia to ELSEczęść.

  • Jeśli nie ma żadnego prawdziwego warunku i żadnej ELSEczęści, ocenia to NULL.

James Jenkins
źródło
2
Chciałem tylko upewnić się, że jeśli mam 3 warunki przypadku, które wszystkie ocenią na prawdę, chciałbym, aby wykonano zadanie tylko pierwszego, który ocenia na prawdę, a nie pozostałych 2 (nawet jeśli oceniano również na prawdę ). Z przykładowego zapytania w moich pytaniach wydaje się, że tak jest. Chciałem tylko potwierdzić. Miałem również nadzieję, że SQL odczyta warunki CASE od góry do dołu. Dzięki!
Juan Velez
15

SQL Server zwykle wykonuje ocenę zwarcia dla instrukcji 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;  

Istnieje jednak kilka rodzajów instrukcji, które od SQL Server 2012 nie powodują prawidłowego zwarcia. Zobacz link z ypercube w komentarzach.

Oracle zawsze dokonuje oceny zwarcia . Zobacz 11.2 Opis języka SQL . Lub porównaj następujące ( 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;

Tego samego testu nie można wykonać w MySQL, ponieważ zwraca NULL dla dzielenia przez zero. ( Skrzypce SQL )

Leigh Riffel
źródło
A co powiesz na to: SQL-Fiddle
ypercubeᵀᴹ
1
Skrzypce dotyczą serwera SQL . Oto odpowiedź Aarona: czy SQL Server odczytuje wszystkie funkcje COALESCE, nawet jeśli pierwszy argument nie ma wartości NULL?
ypercubeᵀᴹ
@ypercube To naprawdę interesujące zachowanie. Sprawdza kod, który działałby w części else, ale wydaje się go ignorować w zależności od tego, jakie inne wyrażenia WHEN istnieją i czy dzielenie przez zero mieści się w MIN, czy nie. Zobacz sqlfiddle.com/#!6/d41d8/4468
Leigh
@ypercube Po przeczytaniu niektórych linków, które opublikowałeś, powiedziałbyś, że istnieje wystarczająca liczba przypadków brzegowych, aby powiedzieć, że odpowiedź na pytanie, czy SQL Server ocenia zwarcie, jest - zwykle?
Leigh Riffel
3
Tak, zgodziłbym się na „zwykle”. Jak wskazuje Aaron na swoją odpowiedź, wystarczy jeden test, aby obalić „CASE zawsze powoduje zwarcie”. Ale zwykle tak jest.
ypercubeᵀᴹ
7

Wygląda na to, że MS SQL Server stosuje również ocenę zwarcia.

W poniższym teście mam 3 testy. Pierwszy jest zawsze prawdziwy, drugi kończy się niepowodzeniem bez odwoływania się do tabeli, a trzeci kończy się niepowodzeniem tylko wtedy, gdy uwzględni się dane.
W tym konkretnym uruchomieniu oba wiersze są zwracane pomyślnie. Jeśli skomentuję pierwszy KIEDY, lub pierwszy i drugi, wtedy dostaję błędy.

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
źródło
1

jeśli instrukcja case zastosowana w tym WHEREwarunku i pierwszy przypadek, gdy instrukcja obejmuje ocenę wartości kolumn z tabeli, a pierwszy wiersz w tabeli nie spełnia tego warunku, instrukcja case przejdzie do następnego przypadku, gdy instrukcja.

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
źródło
1

W MySQL wyjdzie z instrukcji case dla pierwszej prawdziwej opcji. Jeśli masz możliwość podania wielu prawdziwych wartości, chcesz umieścić preferowaną odpowiedź wcześniej w sekwencji.

Obrabować
źródło
Pytanie dotyczy SQL Servera.
James Anderson