SQL Server "Une opération de floating point non valide s'est produite"

Ce n'est pas vraiment un problème parce que je l'ai résolu. Mais, je voulais partager quelque chose qui a mangé mon cerveau aujourd'hui. Alors, lancez cette requête et vérifiez-la:

La requête:

select 2 as ID1,0 as ID2 into #TEMP insert into #TEMP (ID1,ID2) values (2,1),(2,2),(2,0) select case when min(case when ID1=2 and ID2=0 then 0 else 1 end)=0 then 0 else sum(log(ID2)) end from #TEMP 

Le correctif:

 select case when min(case when ID1=2 and ID2=0 then 0 else 1 end)=0 then 0 else sum(log(case when ID1=2 and ID2<>0 then ID2 else 1 end)) end from #TEMP 

Ma requête était plus grande et plus difficile à déboguer, mais que dites-vous du plan que fait MSSQL et du fait qu'il se trompe avec cette requête? Comment peut-il être modifié pour fonctionner, sauf mon petit correctif que j'ai montré avant? Je suppose que calculer des scalaires avant la requête rendrait les choses lentes si les scalaires ne sont pas faciles à calculer et nous calculons pour toutes les valeurs.

SQL Server n'effectue pas d'évaluation de court-circuit (c'est-à-dire qu'il ne doit pas être utilisé). C'est un problème assez bien connu.

Ref:

  • Ne dépendez pas d'un court-circuit d'expression dans T-SQL (pas même avec CASE)

  • Court-circuit

  • Évaluation de court-circuit

  • Le court-circuit de la clause SQL WHERE est-il évalué?

EDIT: J'ai mal compris la question avec ma réponse originale.

Je suppose que vous pourriez append une clause where, comme indiqué ci-dessous. Note complémentaire: cette requête pourrait bénéficier d'un index sur (ID1, ID2).

 select sum(log(convert(float, ID2))) from #TEMP where -- exclude all records with ID1 = 2 if there are any records with ID1 = 2 and ID2 = 0 not exists ( select 1 from #TEMP NoZeros where NoZeros.ID1 = #TEMP.ID1 and NoZeros.ID2 = 0 ) 

Mise à jour: Juste au cas où les performances sont un problème, j'ai obtenu des performances assez comparables à partir de cette requête après avoir ajouté les index suivants:

 create index ix_TEMP_ID1_ID2 on #TEMP (ID1, ID2) create index ix_TEMP_ID2 on #TEMP (ID2) include (ID1) 

Réponse originale

Que diriez-vous de modifier votre fonction de sum comme indiqué ci-dessous?

 sum(case ID2 when 0 then null else log(convert(float, ID2)) end)