Wertet die SQL Server-CASE-Anweisung alle Bedingungen aus oder wird sie bei der ersten TRUE-Bedingung beendet?


44

Werden in der SQL Server- CASEAnweisung (speziell 2008 oder 2012) alle WHENBedingungen ausgewertet oder wird sie beendet, sobald eine WHENKlausel gefunden wird, die als wahr ausgewertet wird? Wenn der gesamte Bedingungssatz durchlaufen wird, bedeutet dies, dass die letzte Bedingung, die als wahr bewertet wurde, die erste Bedingung überschreibt, die als wahr bewertet wurde? Zum Beispiel:

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

Das Ergebnis ist "JA", obwohl die Bedingung "Letzter Zeitpunkt" "NEIN" ergeben sollte. Es scheint, dass es beendet wird, sobald es die erste WAHR-Bedingung findet. Kann jemand bitte bestätigen, ob dies der Fall ist .


5
Sehr eng verbunden: Liest SQL Server die gesamte COALESCE-Funktion, auch wenn das erste Argument nicht NULL ist? (wie COALESCE()in einen CASEAusdruck übersetzt.)
ypercubeᵀᴹ

Antworten:


46

• Gibt den result_expression des ersten input_expression = when_expression zurück , der zu TRUE ausgewertet wird .

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


Dies ist das Standardverhalten von SQL:

  • Ein CASEAusdruck wird zur ersten wahren Bedingung ausgewertet.

  • Wenn keine wahre Bedingung vorliegt, wird das ELSETeil ausgewertet .

  • Wenn es keinen wahren Zustand und kein ELSETeil gibt, wird es zu ausgewertet NULL.


2
Ich wollte nur sicherstellen, dass, wenn ich 3 Fallbedingungen habe, die alle als wahr ausgewertet werden, ich nur die Aufgabe der ersten, die als wahr ausgewertet wird, ausführen möchte, und nicht die anderen 2 (obwohl sie auch als wahr ausgewertet werden) ). Aus der Beispielabfrage in meinen Fragen scheint dies der Fall zu sein. Ich wollte nur bestätigen. Ich hatte auch gehofft, dass SQL die CASE-Bedingungen von oben nach unten liest. Vielen Dank!
Juan Velez

15

SQL Server führt normalerweise eine Kurzschlussauswertung für CASE-Anweisungen ( SQLFiddle ) durch:

--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;  

Es gibt jedoch verschiedene Arten von Anweisungen, die ab SQL Server 2012 nicht mehr richtig kurzschließen. Siehe den Link von ypercube in den Kommentaren.

Oracle führt immer eine Kurzschlussauswertung durch . Siehe die 11.2 SQL-Sprachreferenz . Oder vergleichen Sie Folgendes ( 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;

Derselbe Test kann nicht mit MySQL durchgeführt werden, da NULL für die Division durch Null zurückgegeben wird. ( SQL-Geige )


Wie wäre es damit ?: SQL-Fiddle
ypercubeᵀᴹ


@ypercube Das ist wirklich interessantes Verhalten. Es wertet den Code aus, der im else-Teil ausgeführt werden würde, scheint ihn jedoch zu ignorieren, je nachdem, welche anderen WHEN-Ausdrücke existieren und ob sich die Division durch Null innerhalb eines MIN befindet oder nicht. Siehe sqlfiddle.com/#!6/d41d8/4468
Leigh Riffel

@ypercube Nun, da ich einige der Links gelesen habe, die Sie gepostet haben, würden Sie sagen, dass es genügend Randfälle gibt, um zu sagen, dass die Antwort auf die Frage, ob SQL Server eine Kurzschlussbewertung durchführt, in der Regel lautet?
Leigh Riffel

3
Ja, ich würde "normalerweise" zustimmen. Wie Aaron auf seine Antwort hinweist, reicht ein Test aus, um den "FALL immer Kurzschlüsse" zu widerlegen. Aber normalerweise tut es das.
ypercubeᵀᴹ

7

Es scheint, dass MS SQL Server auch eine Kurzschlussauswertung verwendet.

Im folgenden Test habe ich 3 Tests. Der erste ist immer wahr, der zweite schlägt fehl, ohne auf die Tabelle zu verweisen, und der dritte schlägt nur fehl, wenn die Daten berücksichtigt werden.
In diesem bestimmten Lauf werden beide Zeilen erfolgreich zurückgegeben. Wenn ich das erste WANN oder das erste und das zweite auskommentiere, bekomme ich Fehler.

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

Wenn die in der WHEREBedingung verwendete case-Anweisung und die erste when-Anweisung das Auswerten von Spaltenwerten aus der Tabelle umfassen und die erste Zeile in der Tabelle diese Bedingung nicht erfüllt, wird die case-Anweisung mit der when-Anweisung für den nächsten case fortgesetzt.

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 wird die case-Anweisung für die erste true-Option beendet. Wenn Sie die Möglichkeit haben, mehrere wahre Werte anzugeben, möchten Sie die bevorzugte Antwort früher in die Sequenz einfügen.


Die Frage bezieht sich auf SQL Server.
James Anderson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.