Comment éviter la “division par zéro” erreur SQL?
J'ai ce message d'erreur:
Msg 8134, Niveau 16, État 1, Ligne 1 erreur de division par zéro rencontrés.
Quelle est la meilleure façon d'écrire du code SQL de sorte que je ne verrai jamais ce message d'erreur?
Je pourrais le faire de la façon suivante:
- Ajouter une clause where pour que mon diviseur n'est jamais nulle
Ou
- Je pourrais ajouter une instruction du cas, de sorte qu'il existe un traitement spécial pour le zéro.
Est la meilleure façon d'utiliser un NULLIF
clause?
Est-il de meilleure façon, ou comment cela peut-il être appliqué?
- Peut-être certains de validation des données est dans l'ordre.
Vous devez vous connecter pour publier un commentaire.
Afin d'éviter une Division par zéro" de l'erreur que nous avons programmé comme ceci:
Mais ici c'est tellement plus agréable façon de le faire:
Maintenant, le seul problème est de se rappeler l'NullIf peu, si j'utilise la touche'/'.
IsNull
au lieu deNullIf
? Essayez-le vous-même!SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);
À moins que par "sauts" tu veux dire que renvoie une valeur NULL? Vous pouvez convertir ce que vous voulez avecIsNull
ouCoalesce
.SELECT 1 / NULLIF(NULL, 0)
échoue, mais c'est parce queNULLIF()
besoins de connaître le type du premier argument. Cette altération exemple fonctionne très bien:SELECT 1 / NULLIF(CAST(NULL AS INT), 0)
. Dans la vraie vie, vous allez d'approvisionnement d'une colonne de table deNULLIF()
plutôt qu'unNULL
constante. Depuis des colonnes de la table ont connu les types de données, cela fonctionne aussi très bien:SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable
.Dans le cas où vous voulez retourner à zéro, dans le cas d'un zéro devision qui allait se passer, vous pouvez utiliser:
Pour chaque diviseur de zéro, vous obtiendrez un zéro dans le jeu de résultats.
Ce qui semblait être le meilleur correctif pour ma situation lorsque essayant de répondre à la division par zéro, ce qui arrive dans mes données.
Supposons que vous voulez calculer le ratio hommes /femmes pour les différents les clubs de l'école, mais vous découvrez que la requête suivante échoue et les enjeux d'une division par zéro erreur lorsqu'il tente de calculer le ratio pour le Seigneur des Anneaux Club, qui n'a pas de femmes:
Vous pouvez utiliser la fonction
NULLIF
pour éviter la division par zéro.NULLIF
compare deux expressions et renvoie la valeur null si elles sont égales ou la première expression autrement.La réécriture de la requête comme suit:
Un nombre divisé par
NULL
donneNULL
, et aucune erreur n'est générée.select males/(males+females), females/(males+females)
. Cela vous donnera la répartition en pourcentage de mâles et de femelles dans un club, comme 31% des hommes et 69% des femmes.Vous pouvez également le faire au début de la requête:
Donc, si vous avez quelque chose comme
100/0
il retournera NULL. J'ai seulement fait ce pour les requêtes simples, donc je ne sais pas comment il va affecter plus/plus complexes.Vous pouvez au moins arrêter la requête à partir de la rupture avec un message d'erreur et retour
NULL
si il y a une division par zéro:Cependant, je tiens à JAMAIS convertir cette valeur à Zéro avec
coalesce
comme il est montré dans cet autre réponse, qui a eu beaucoup de upvotes. Ce qui est totalement faux dans un sens mathématique, et il est même dangereux à mesure que votre demande sera probablement de retour tort et à des résultats trompeurs.EDIT:
J'ai beaucoup de downvotes sur cette récemment...j'ai donc pensé que je pourrais juste ajouter une remarque que cette réponse a été écrit avant que la question a subi sa plus récente édition, où retourner null a été mis en évidence comme une option...qui semble très acceptable. Certains de ma réponse s'adressait à des préoccupations comme celle de Edwardo, dans les commentaires, qui semblait préconiser le retour d'un 0. C'est le cas, j'ai été de s'insurger contre.
RÉPONSE:
Je pense qu'il y a un problème sous-jacent ici, qui est que la division par 0 n'est pas légal. C'est une indication que quelque chose est fundementally mal. Si vous êtes à la division par zéro, vous essayez de faire quelque chose qui n'a pas de sens mathématiquement, donc pas de réponse numérique, vous pouvez obtenir sera valide. (Utilisation de null dans ce cas, est raisonnable, car il n'est pas une valeur qui sera utilisée plus tard dans des calculs mathématiques).
Donc Edwardo demande dans les commentaires "que si l'utilisateur met en 0?", et il préconise, il devrait être correct pour obtenir un 0 en retour. Si l'utilisateur met à zéro de la quantité, et vous voulez retourné 0 quand ils le font, alors vous devriez mettre dans le code à l'entreprise des règles de niveau de capture de valeur et de retour 0...pas de certains cas spécial où la division par 0 = 0.
C'est une différence subtile, mais c'est important...parce que la prochaine fois que quelqu'un appelle votre fonction et s'attend à faire la bonne chose, et il fait quelque chose de funky qui n'est pas mathématiquement correct, mais simplement gère le particulier edge cas il a une bonne chance de mordre quelqu'un plus tard. Vous n'êtes pas vraiment division par 0...vous êtes juste de retour d'une mauvaise réponse à une mauvaise question.
Imagine que je suis codage quelque chose, et je le visser en place. Je devrais être de la lecture dans un rayonnement de mesure mise à l'échelle de la valeur, mais dans un étrange cas de bord je n'avais pas prévu, j'ai lu dans 0. Puis je déposer ma valeur dans votre fonction...vous me rendre un 0! Hourra, pas de rayonnement! Sauf que c'est vraiment là et c'est juste que j'étais de passage dans une mauvaise valeur...mais je n'ai aucune idée. Je veux de la division de jeter l'erreur, car c'est le drapeau que quelque chose est incorrect.
En attrapant le zéro avec un nullif(), alors la résultante nulle avec un isnull (), vous pouvez contourner votre erreur de division par zéro.
Le remplacement de "division par zéro" avec zéro est controversée, mais c'est pas non plus la seule option. Dans certains cas, le remplacement de 1 est (relativement) approprié. Je me retrouve souvent à l'aide de
quand je suis à la recherche des changements dans les scores/compte, et que vous voulez par défaut la valeur 1 si je n'ai pas de données. Par exemple
Plus souvent que pas, en fait, j'ai calculé ce ratio à un autre endroit, pas moins, car il peut jeter un peu de très grands facteurs d'ajustement pour la basse dénominateurs. Dans ce cas, je serais normalement de contrôle pour OldSampleScore est supérieure à un seuil; puis qui s'oppose à zéro. Mais parfois, le "hack" est approprié.
J'ai écrit une fonction a tout à l'arrière de la poignée pour mon procédures stockées:
Divisor
non-zéroPour la mise à jour de Sql:
Il n'y a pas de magie paramètre global au tour de la division par 0 exceptions off". L'opération est à jeter, car le sens mathématique de x/0 est différent de NULL sens, de sorte qu'il ne peut pas retourner la valeur NULL.
Je suppose que vous êtes en prenant soin de l'évidence et de vos questions ont des conditions qui devrait éliminer les enregistrements avec le diviseur de 0 et de ne jamais évaluer la division. L'habituel "chasse aux sorcières" est que la plupart des développeurs s'attendent à SQL à se comporter comme des langages procéduraux et offre opérateur logique de court-circuit, mais il ne PAS. Je vous recommande de lire cet article: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html
Ici est une situation où l'on peut diviser par zéro. L'entreprise de la règle, c'est que pour calculer la rotation des stocks, vous prenez le coût des marchandises vendues pour une période, annualiser il. Après vous avez le nombre annualisé, vous divisez par le stock moyen pour la période.
Je cherche à calculer le nombre de tours d'inventaire qui se produisent dans une période de trois mois. J'ai calculé que j'ai le Coût des Marchandises vendues au cours de la période de trois mois de 1 000$. Le taux annuel des ventes est $4,000 ($1,000/3)*12. Le début de l'inventaire est de 0. Le stock final est de 0. Ma moyenne de l'inventaire est maintenant à 0. J'ai de vente de 4000 $par année, et pas de stock. Cela donne un nombre infini de tours. Cela signifie que tout mon inventaire est en cours de conversion et achetés par les clients.
C'est une règle d'entreprise de la manière de calculer la rotation des stocks.
Filtrer des données à l'aide d'une clause where de sorte que vous n'obtenez pas de valeurs à 0.
Parfois, 0 peut ne pas être appropriée, mais parfois 1 ne convient pas non plus. Parfois, un saut de 0 à 100 000 000 décrite comme 1 ou à 100 pour cent changement peut aussi être trompeuse. 100 000 000 d' % pourrait être appropriée dans ce scénario. Cela dépend de ce genre de conclusions que vous avez l'intention de tirer sur la base des pourcentages ou de rapports.
Par exemple, un très petit-point de vente en mouvement à partir de 2-4 vendus et une très grande point de vente en changeant de 1 000 000 à 2 000 000 d'vendu peut signifier des choses très différentes pour un analyste ou de gestion, mais permettrait à la fois de venir à travers comme 100% ou 1 changement.
Il pourrait être plus facile d'isoler les valeurs NULL que de parcourir sur une bande de 0% ou de 100% des lignes mélangé avec de légitimes de données. Souvent, un 0 dans le dénominateur peut indiquer une erreur ou valeur manquante, et vous ne voulez pas vous contenter de remplir une valeur arbitraire, juste pour rendre votre dataset look bien rangé.
Vous pouvez gérer l'erreur de façon appropriée lorsqu'il se propage de retour au programme appelant (ou l'ignorer si c'est ce que vous voulez). En C# les erreurs qui se produisent dans SQL va lever une exception que je puisse les attraper et de gérer dans mon code, tout comme toute autre erreur.
Je suis d'accord avec Beska dans que vous n'avez pas à masquer l'erreur. Vous ne pouvez pas être en contact avec un réacteur nucléaire, mais de masquage d'erreurs, en général, est une mauvaise programmation de la pratique. C'est l'une des raisons pour lesquelles la plupart des langages de programmation modernes de mettre en œuvre la gestion structurée des exceptions à découpler la valeur de retour avec une erreur /état code. Cela est particulièrement vrai lorsque vous êtes à faire des mathématiques. Le plus gros problème est que vous ne pouvez pas distinguer correctement calculé 0 est renvoyée ou un 0 comme le résultat d'une erreur. Au lieu de cela toute la valeur retournée est la valeur calculée et si quelque chose va mal, une exception est levée. Cela va bien sûr dépendre de la façon dont vous accédez à la base de données et du langage que vous utilisez, mais vous devriez toujours être en mesure d'obtenir un message d'erreur que vous pouvez faire.
Utilisation
NULLIF(exp,0)
, mais de cette manière -NULLIF(ISNULL(exp,0),0)
NULLIF(exp,0)
des pauses si exp estnull
maisNULLIF(ISNULL(exp,0),0)
ne cassera pasC'est la façon dont je l'ai corrigé:
IIF(ValueA != 0 Total /ValueA, 0)
Il peut être enveloppé dans une mise à jour:
ENSEMBLE du Pct = IIF(ValueA != 0 Total /ValueA, 0)
Ou dans un select:
SÉLECTIONNEZ IIF(ValueA != 0 Total /ValueA, 0) du Pct from Tablename;
Pensées?