L'instruction SQL Server CASE évalue-t-elle toutes les conditions ou se termine-t-elle sur la première condition VRAIE?

44

L'instruction SQL Server (2008 ou 2012, en particulier) CASEévalue-t-elle toutes les WHENconditions ou se ferme-t-elle une fois qu'elle trouve une WHENclause évaluée à true? Si elle passe par l’ensemble des conditions, cela signifie-t-il que la dernière condition évaluée comme vraie remplace ce que la première condition évaluée comme vraie a fait? Par exemple:

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

Le résultat est "OUI" même si la dernière condition à remplir doit être évaluée à "NON". Il semble qu'il se ferme une fois qu'il a trouvé la première condition VRAIE. Quelqu'un peut-il s'il vous plaît confirmer si tel est le cas .

Juan Velez
la source
5
Très étroitement lié: SQL Server lit-il l'intégralité d'une fonction COALESCE même si le premier argument n'est pas NULL? (comme COALESCE()traduit dans une CASEexpression.)
ypercubeᵀᴹ

Réponses:

46

• Retourne le result_expression du premier input_expression = when_expression évalué à TRUE .

Référence http://msdn.microsoft.com/en-us/library/ms181765.aspx


C'est le comportement standard de SQL:

  • Une CASEexpression est évaluée à la première condition vraie.

  • S'il n'y a pas de vraie condition, la ELSEpartie est évaluée .

  • S'il n'y a pas de condition vraie ni de ELSEpièce, le résultat est évalué à NULL.

James Jenkins
la source
2
Je voulais juste m'assurer que si j'avais 3 conditions de cas qui seraient toutes évaluées comme vraies, je voudrais seulement que la tâche de la première tâche qui évalue comme vraie soit exécutée et non les 2 autres (même si elles sont aussi évaluées comme vraies) ). Cela semble être le cas d'après la requête donnée en exemple dans mes questions. Je voulais juste confirmer. J'espérais également que SQL lit les conditions CASE de haut en bas. Merci!
Juan Velez
15

SQL Server effectue généralement une évaluation de court-circuit pour les instructions 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;  

Il existe cependant plusieurs types d'instructions qui, à partir de SQL Server 2012, ne court-circuitent pas correctement. Voir le lien de ypercube dans les commentaires.

Oracle effectue toujours une évaluation de court-circuit . Voir la Référence du langage SQL 11.2 . Ou comparez ce qui suit ( 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;

Ce même test ne peut pas être réalisé avec MySQL car il renvoie NULL pour une division par zéro. ( Violon SQL )

Leigh Riffel
la source
Que diriez-vous de ça ?: SQL-Fiddle
ypercubeᵀᴹ
1
Le violon concerne SQL-Server . C'est la réponse d'Aaron: SQL Server lit-il toutes les fonctions COALESCE même si le premier argument n'est pas NULL?
Ypercubeᵀᴹ
@ypercube C'est un comportement vraiment intéressant. Il évalue le code qui s'exécutera dans la partie else, mais semble l'ignorer en fonction des autres expressions WHEN existantes et du fait que la division par zéro se situe à l'intérieur d'un MIN ou non. Voir sqlfiddle.com/#!6/d41d8/4468
Leigh Riffel
@ypercube Maintenant que j'ai lu le lien que vous avez posté, diriez-vous qu'il y a suffisamment de cas extrêmes pour dire que la réponse à la question de savoir si SQL Server effectue l'évaluation de court-circuit est - généralement?
Leigh Riffel
3
Oui, je suis d'accord sur "d'habitude". Comme le souligne Aaron dans sa réponse, un seul test suffit à réfuter le "CAS toujours des courts-circuits". Mais c'est généralement le cas.
Ypercubeᵀᴹ
7

Il semble que MS SQL Server utilise également une évaluation de court-circuit.

Dans le test suivant, j'ai 3 tests. Le premier est toujours vrai, le second échoue sans référencer la table et le troisième échoue uniquement lorsque les données sont prises en compte.
Dans cette exécution particulière, les deux lignes sont renvoyées avec succès. Si je commente le premier QUAND, ou le premier et le second, je reçois des échecs.

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
la source
1

Si l'instruction case utilisée dans la WHEREcondition et la première instruction case quand impliquent l'évaluation des valeurs de colonne de la table et que la première ligne de la table ne satisfait pas cette condition, l'instruction case passera à l'instruction case suivante.

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
la source
1

En MySQL, la casse est supprimée à la première vraie option. Si vous avez la possibilité de plusieurs valeurs vraies, vous souhaitez placer la réponse préférée plus tôt dans la séquence.

Rob
la source
La question concerne SQL Server.
James Anderson