Wie vermeide ich den Fehler "Teilen durch Null" in SQL?


363

Ich habe diese Fehlermeldung:

Meldung 8134, Ebene 16, Status 1, Zeile 1 Fehler beim Teilen durch Null aufgetreten.

Was ist der beste Weg, um SQL-Code zu schreiben, damit ich diese Fehlermeldung nie wieder sehe?

Ich könnte eine der folgenden Aktionen ausführen:

  • Fügen Sie eine where-Klausel hinzu, damit mein Divisor niemals Null ist

Oder

  • Ich könnte eine Fallbeschreibung hinzufügen, damit es eine Sonderbehandlung für Null gibt.

Ist der beste Weg, eine NULLIFKlausel zu verwenden?

Gibt es einen besseren Weg oder wie kann dies durchgesetzt werden?


7
Möglicherweise ist eine Datenüberprüfung angebracht.
Anthony

Antworten:


644

Um einen Fehler "Division durch Null" zu vermeiden, haben wir ihn folgendermaßen programmiert:

Select Case when divisor=0 then null
Else dividend / divisor
End ,,,

Aber hier ist eine viel schönere Art, es zu tun:

Select dividend / NULLIF(divisor, 0) ...

Jetzt besteht das einzige Problem darin, sich das NullIf-Bit zu merken, wenn ich die Taste "/" verwende.


13
Eine viel schönere Methode "Dividende auswählen / nullif (Divisor, 0) ..." bricht ab, wenn Divisor NULL ist.
Anderson

8
@ Anderson Das stimmt überhaupt nicht. Sind Sie sicher, dass Sie nicht versehentlich IsNullstatt verwendet haben NullIf? Versuch es selber! SELECT Value,1/NullIf(Value,0)FROM(VALUES(0),(5.0),(NULL))x(Value);Wenn nicht mit "Pausen" gemeint ist, wird NULL zurückgegeben? Sie können das mit IsNulloder in alles konvertieren, was Sie wollen Coalesce.
ErikE

1
@ErikE, es ist wahr ... versuchen Sie es auszuführen ... wählen Sie 1 / nullif (null, 0) ... Sie erhalten "Der Typ des ersten Arguments für NULLIF kann nicht die NULL-Konstante sein, da der Typ des ersten Arguments hat bekannt sein." Behandeln Sie dies mit "coalesce (FieldName, 0)" ... zB wählen Sie 1 / nullif (coalesce (null, 0), 0)
John Joseph

1
@ JohnJoseph Ich kann nicht sagen, ob Sie mir zustimmen oder mit mir streiten.
ErikE

1
@ JohnJoseph Schauen Sie sich den Fehler genauer an. Ja, SELECT 1 / NULLIF(NULL, 0)schlägt fehl, aber es liegt daran NULLIF(), dass der Datentyp des ersten Arguments bekannt sein muss. Dieses geänderte Beispiel funktioniert einwandfrei : SELECT 1 / NULLIF(CAST(NULL AS INT), 0). Im wirklichen Leben werden Sie NULLIF()eher eine Tabellenspalte als eine NULLKonstante angeben. Da Tabellenspalten bekannte Datentypen haben, funktioniert dies auch einwandfrei : SELECT 1 / NULLIF(SomeNullableColumn, 0) FROM SomeTable.
MarredCheese

180

Wenn Sie Null zurückgeben möchten, falls eine Null-Abweichung auftreten würde, können Sie Folgendes verwenden:

SELECT COALESCE(dividend / NULLIF(divisor,0), 0) FROM sometable

Für jeden Divisor, der Null ist, erhalten Sie eine Null in der Ergebnismenge.


9
Einige Benchmarks zeigen, dass COALESCE etwas langsamer als ISNULL ist. COALESCE gehört jedoch zu den Standards und ist daher tragbarer.
Paul Chernoch

37
Wenn jemand anderes nicht sofort versteht, warum dies funktioniert, gibt NULLIF (d, 0) NULL zurück, wenn d 0 ist. In SQL gibt das Teilen durch NULL NULL zurück. Die Koaleszenz ersetzt die resultierende NULL durch 0.
GuiSim

16
@SQLGeorge Obwohl ich Ihrem Argument zustimme, beachten Sie bitte, dass es Fälle gibt, in denen es mehr darum geht, was statistisch korrekt als mathematisch korrekt ist. In einigen Fällen ist bei Verwendung von Statistikfunktionen 0 oder sogar 1 ein akzeptables Ergebnis, wenn der Divisor Null ist.
Athafoud

10
Kann mir jemand erklären, warum das schlecht ist? Wenn ich versuche, ein Prozent herauszufinden und der Divisor Null ist, möchte ich mit Sicherheit, dass das Ergebnis Null Prozent ist.
Todd Sharp

10
Ich denke, dass @George und @ James / Wilson die gestellte Frage grundlegend missverstehen. Es gibt sicherlich Geschäftsanwendungen, bei denen die Rückgabe einer "0" angemessen ist, auch wenn dies aus mathematischer Sicht technisch nicht zutrifft.
Sean Branchaw

66

Dies schien die beste Lösung für meine Situation zu sein, wenn ich versuchte, die Division durch Null zu beheben, was in meinen Daten vorkommt.

Angenommen, Sie möchten das Verhältnis von Männern zu Frauen für verschiedene Schulklubs berechnen, stellen jedoch fest, dass die folgende Abfrage fehlschlägt und einen Fehler beim Teilen durch Null ausgibt, wenn versucht wird, das Verhältnis für den Lord of the Rings-Club zu berechnen, der keine Frauen hat ::

SELECT club_id, males, females, males/females AS ratio
  FROM school_clubs;

Mit dieser Funktion können Sie NULLIFeine Division durch Null vermeiden. NULLIFvergleicht zwei Ausdrücke und gibt null zurück, wenn sie gleich sind, oder den ersten Ausdruck andernfalls.

Schreiben Sie die Abfrage wie folgt um:

SELECT club_id, males, females, males/NULLIF(females, 0) AS ratio
  FROM school_clubs;

Jede Zahl geteilt durch NULLgibt NULL, und es wird kein Fehler erzeugt.


6
Ja, das ist viel besser als diese andere Antwort, die so viele positive Stimmen hat. In Ihrer Lösung haben Sie mindestens NULL, was darauf hinweist, dass Sie kein korrektes Ergebnis liefern können. Wenn Sie das Ergebnis jedoch von NULL in Null konvertieren, erhalten Sie einfach falsche und irreführende Ergebnisse.
SQL Police

8
Übrigens, wenn Sie ein Verhältnis von Männern zu Frauen berechnen möchten, dann schlage ich vor, es besser mit der Summe zu vergleichen, wie folgt : select males/(males+females), females/(males+females). Dies gibt Ihnen die prozentuale Verteilung von Männern und Frauen in einem Club, wie 31% Männer, 69% Frauen.
SQL Police

44

Sie können dies auch zu Beginn der Abfrage tun:

SET ARITHABORT OFF 
SET ANSI_WARNINGS OFF

Wenn Sie also so etwas haben, 100/0wird NULL zurückgegeben. Ich habe dies nur für einfache Abfragen getan, daher weiß ich nicht, wie sich dies auf längere / komplexe Abfragen auswirkt.


1
Funktioniert bei mir. In meinem Fall muss ich die Divide-Operation in der WHERE-Klausel verwenden. Ich bin mir sicher, dass es keinen Nullteiler gibt, denn wenn ich WHERE out kommentiere, gibt es bei den Ergebnissen keine Nullwerte. Aber irgendwie wird der Abfrageoptimierer beim Filtern durch Null geteilt. SET ARITHABORT OFF SET und ANSI_WARNINGS OFF funktionieren - nach 2 Tagen Kampf mit Division durch Null in der WHERE-Klausel. Danke!
huhu78

2
Das "fühlt" sich so dreckig an, aber ich liebe es! Es wurde in einer Abfrage benötigt, die eine Aggregation durchführt und die CASE-Anweisung verwendet, war keine Option, da ich dann diese Spalte zur GROUP BY hinzufügen musste, wodurch die Ergebnisse vollständig geändert wurden. Wenn Sie die anfängliche Abfrage zu einer Unterauswahl machen und dann eine GROUP BY-Anweisung für die äußere Abfrage ausführen, werden auch die Ergebnisse geändert, da eine Teilung erforderlich ist.
Andrew Steitz

1
OK, also ich mag diese "Lösung" immer noch, aber wie viele von Ihnen wahrscheinlich meinten, musste es einen "saubereren" Weg geben. Was ist, wenn ich vergessen habe, die Warnungen wieder zu aktivieren? Oder hat jemand meinen Code getarnt (das passiert nie, oder?) Und nicht über die Warnungen nachgedacht? Wie auch immer, sah andere Antworten über NULLIF (). Ich wusste von NULLIF (), wusste aber nicht, dass das Teilen durch NULL NULL zurückgibt (ich dachte, es wäre ein Fehler). Also ... ich ging mit folgendem: ISNULL ((SUM (foo) / NULLIF (SUM (bar), 0)), 0) AS Avg
Andrew Steitz

2
Ich kannte diese Lösung nicht. Ich bin mir nicht sicher, ob es mir gefällt, aber es könnte nützlich sein, es eines Tages zu wissen. Vielen Dank.
Henrik Staun Poulsen

1
Dies ist die einfachste Lösung. Beachten Sie jedoch, dass dies die Leistung beeinträchtigt. Von docs.microsoft.com/en-us/sql/t-sql/statements/… : "Das Setzen von ARITHABORT auf OFF kann sich negativ auf die Abfrageoptimierung auswirken und zu Leistungsproblemen führen."
Monoblaine

36

Sie können zumindest verhindern, dass die Abfrage mit einem Fehler unterbrochen wird, und zurückkehren, NULLwenn eine Division durch Null vorliegt :

SELECT a / NULLIF(b, 0) FROM t 

Allerdings würde ich nie diese auf Null konvertieren , coalescewie es in der anderen Antwort gezeigt, die viele upvotes bekamen. Dies ist im mathematischen Sinne völlig falsch und sogar gefährlich, da Ihre Anwendung wahrscheinlich falsche und irreführende Ergebnisse liefert.


32

BEARBEITEN: Ich bekomme in letzter Zeit viele Abstimmungen dazu ... also dachte ich, ich würde nur eine Notiz hinzufügen, dass diese Antwort geschrieben wurde, bevor die Frage zuletzt bearbeitet wurde, wobei die Rückgabe von null als Option hervorgehoben wurde. .das scheint sehr akzeptabel. Einige meiner Antworten richteten sich in den Kommentaren an Bedenken wie die von Edwardo, der anscheinend die Rückgabe einer 0 befürwortete. Dies ist der Fall, gegen den ich mich beschimpfte.

ANTWORT: Ich denke, hier liegt ein Problem zugrunde, nämlich dass die Division durch 0 nicht legal ist. Es ist ein Hinweis darauf, dass etwas grundlegend falsch ist. Wenn Sie durch Null teilen, versuchen Sie, etwas zu tun, das mathematisch nicht sinnvoll ist, sodass keine numerische Antwort gültig ist. (Die Verwendung von null ist in diesem Fall sinnvoll, da es sich nicht um einen Wert handelt, der in späteren mathematischen Berechnungen verwendet wird.)

Also fragt Edwardo in den Kommentaren "Was ist, wenn der Benutzer eine 0 eingibt?" Und er befürwortet, dass es in Ordnung sein sollte, eine 0 als Gegenleistung zu erhalten. Wenn der Benutzer den Betrag auf Null setzt und Sie möchten, dass 0 zurückgegeben wird, sollten Sie Code auf der Ebene der Geschäftsregeln eingeben, um diesen Wert abzufangen und 0 zurückzugeben. Es gibt keinen Sonderfall, in dem Division durch 0 = 0.

Das ist ein subtiler Unterschied, aber es ist wichtig ... weil das nächste Mal, wenn jemand Ihre Funktion aufruft und erwartet, dass sie das Richtige tut, etwas Funky funktioniert, das mathematisch nicht korrekt ist, sondern nur den speziellen Randfall behandelt, den es hat gute Chance, später jemanden zu beißen. Sie teilen nicht wirklich durch 0 ... Sie geben nur eine schlechte Antwort auf eine schlechte Frage zurück.

Stellen Sie sich vor, ich codiere etwas und vermassle es. Ich sollte einen Skalierungswert für die Strahlungsmessung einlesen, aber in einem seltsamen Randfall, den ich nicht erwartet hatte, las ich 0 ein. Dann lasse ich meinen Wert in Ihre Funktion fallen ... Sie geben mir eine 0 zurück! Hurra, keine Strahlung! Außer es ist wirklich da und es ist nur so, dass ich einen schlechten Wert abgegeben habe ... aber ich habe keine Ahnung. Ich möchte, dass die Division den Fehler auslöst, weil es die Flagge ist, dass etwas nicht stimmt.


15
Ich stimme dir nicht zu. Ihre Geschäftsregeln sollten niemals illegale Mathematik betreiben. Wenn Sie am Ende so etwas tun, ist Ihr Datenmodell höchstwahrscheinlich falsch. Wann immer Sie auf eine Division durch 0 stoßen, sollten Sie darüber nachdenken, ob die Daten NULL statt 0 gewesen sein sollten.
Remus Rusanu

32
Ich kann nicht glauben, dass ich von jemandem abgelehnt wurde, der fragt, ob ich jemals "wirklich programmiert" habe? weil ich sage, es richtig zu machen, anstatt faul zu sein. Seufzer
Beska

11
Es tut mir leid, ich wollte dich nicht beleidigen. Aber die Frage ist in vielen gängigen LOB-Anwendungen durchaus gültig, und die Beantwortung mit "Division durch 0 ist nicht legal" bringt meiner Meinung nach keinen Mehrwert.
Eduardo Molteni

2
@ JackDouglas Richtig. Dies ist ein Fall, in dem die Geschäftsregeln einen Sonderfall auf besondere Weise behandeln sollen. Es sollte jedoch nicht die zugrunde liegende Mathematik sein, die ein Leerzeichen zurückgibt. Es sollte die Geschäftsregel sein. Die akzeptierte Antwort gibt eine Null zurück, was eine gute Möglichkeit ist, damit umzugehen. Eine Ausnahme zu werfen wäre auch in Ordnung. Es wäre wohl ideal, es zu erkennen und zu handhaben, bevor es in die SQL geht. Das Bereitstellen einer Funktion, die andere Dinge aufrufen könnten und die einen mathematisch falschen Wert zurückgibt, ist nicht der richtige Weg, da dieser Sonderfall möglicherweise nicht für diese anderen Aufrufer gilt.
Beska

4
@ JackDouglas Ja, das ist eine gute Zusammenfassung, der ich zustimme. Ursprünglich schien die Frage so formuliert zu sein: "Was kann ich tun, um diesen Fehler einfach zu verbergen?" Seitdem hat es sich weiterentwickelt. Die Rückgabe einer Null, die Antwort, zu der er schließlich kommt, scheint eine vernünftige Antwort zu sein. (Ich habe mich nachdrücklich dafür
ausgesprochen,

28
SELECT Dividend / ISNULL(NULLIF(Divisor,0), 1) AS Result from table

Indem Sie die Null mit einem nullif () und dann die resultierende Null mit einem isnull () abfangen, können Sie Ihre Division durch einen Nullfehler umgehen.


3
Aufgrund seiner Länge wurde Ihre Antwort zum Löschen empfohlen. Beachten Sie, dass es immer besser ist, eine kleine Erklärung zu dem hinzuzufügen, was Sie vorschlagen - auch wenn es sehr einfach erscheint;)
Trinimon

10

Das Ersetzen von "durch Null teilen" durch Null ist umstritten - aber es ist auch nicht die einzige Option. In einigen Fällen ist das Ersetzen durch 1 (angemessen) angemessen. Ich finde mich oft mit

 ISNULL(Numerator/NULLIF(Divisor,0),1)

Wenn ich Verschiebungen in Punktzahlen / Zählungen betrachte und standardmäßig 1 verwenden möchte, wenn ich keine Daten habe. Zum Beispiel

NewScore = OldScore *  ISNULL(NewSampleScore/NULLIF(OldSampleScore,0),1) 

Meistens habe ich dieses Verhältnis tatsächlich woanders berechnet (nicht zuletzt, weil es einige sehr große Anpassungsfaktoren für niedrige Nenner auslösen kann. In diesem Fall würde ich normalerweise steuern, dass OldSampleScore größer als ein Schwellenwert ist, der dann Null ausschließt Aber manchmal ist der "Hack" angemessen.


1
@ N Mason; Ja, manchmal ist 1 eine Option. Aber wie erinnerst du dich an den ISNULL-Teil, wenn du den Backslash eingibst?
Henrik Staun Poulsen

1
Entschuldigung Henrik - ich bin mir nicht sicher, ob ich die Frage verstehe.
N Mason

6

Ich habe vor einiger Zeit eine Funktion geschrieben, um sie für meine gespeicherten Prozeduren zu handhaben :

print 'Creating safeDivide Stored Proc ...'
go

if exists (select * from dbo.sysobjects where  name = 'safeDivide') drop function safeDivide;
go

create function dbo.safeDivide( @Numerator decimal(38,19), @divisor decimal(39,19))
   returns decimal(38,19)
begin
 -- **************************************************************************
 --  Procedure: safeDivide()
 --     Author: Ron Savage, Central, ex: 1282
 --       Date: 06/22/2004
 --
 --  Description:
 --  This function divides the first argument by the second argument after
 --  checking for NULL or 0 divisors to avoid "divide by zero" errors.
 -- Change History:
 --
 -- Date        Init. Description
 -- 05/14/2009  RS    Updated to handle really freaking big numbers, just in
 --                   case. :-)
 -- 05/14/2009  RS    Updated to handle negative divisors.
 -- **************************************************************************
   declare @p_product    decimal(38,19);

   select @p_product = null;

   if ( @divisor is not null and @divisor <> 0 and @Numerator is not null )
      select @p_product = @Numerator / @divisor;

   return(@p_product)
end
go

2
Hallo Ron, nette Lösung, außer dass sie einen begrenzten Datentyp (4 Dezimalstellen) hat und unsere @divisors auch negativ sein können. Und wie erzwingen Sie die Verwendung? TIA Henrik Staun Poulsen
Henrik Staun Poulsen

1
Ich habe es ziemlich schnell geschafft, um ein bestimmtes Problemszenario zu behandeln. Einzelne Entwickler-App, daher ist die Durchsetzung bis auf mein Gedächtnis nicht so schwierig. :-)
Ron Savage

5
Trotz der print-Anweisung handelt es sich nicht um einen gespeicherten Prozess, sondern um eine skalare UDF. Dies bringt Sie in MS-SQL um, wenn es Teil einer Abfrage ist.
Mark Sowul

4
Ich stimmte Mark Sowuls Behauptung zu, dass die Skalarfunktion Schmerzen verursachen wird. Dies ist ein schrecklicher Vorschlag in T-SQL, tun Sie es nicht! Skalarfunktionen sind Leistungszerstörer! Inline-Tabellenwertfunktionen sind die einzigen guten Benutzerfunktionen in SQL Server (möglicherweise mit Ausnahme von CLR-Funktionen, die eine gute Leistung erbringen können).
Davos

4
  1. Fügen Sie eine CHECK-Einschränkung hinzu, die erzwingt Divisor, dass sie nicht Null ist
  2. Fügen Sie dem Formular einen Validator hinzu, damit der Benutzer keine Nullwerte in dieses Feld eingeben kann.

1
Ich fange an, CHECK-Einschränkungen immer mehr zu mögen.
Henrik Staun Poulsen

4

Für Update-SQLs:

update Table1 set Col1 = Col2 / ISNULL(NULLIF(Col3,0),1)

3
Hallo Vijay, ja, das wird funktionieren, aber ... Ich würde vorsichtig mit dem ISNULL-Teil sein, bei dem Sie sich am Ende durch NULL teilen. Ich möchte dem Benutzer lieber signalisieren, dass das Ergebnis unbekannt ist, da der Divisor Null ist.
Henrik Staun Poulsen

2
Es hat mich in komplizierten Unterfragen gerettet, danke.
QMaster

3

Es gibt keine magische globale Einstellung "Division durch 0 Ausnahmen ausschalten". Die Operation muss werfen, da sich die mathematische Bedeutung von x / 0 von der NULL-Bedeutung unterscheidet und daher nicht NULL zurückgeben kann. Ich gehe davon aus, dass Sie sich um das Offensichtliche kümmern und Ihre Abfragen Bedingungen haben, die die Datensätze mit dem 0-Teiler beseitigen und die Teilung niemals bewerten sollten. Das übliche "Gotcha" ist, dass die meisten Entwickler erwarten, dass sich SQL wie prozedurale Sprachen verhält und einen logischen Operator-Kurzschluss bietet, dies jedoch NICHT . Ich empfehle Ihnen, diesen Artikel zu lesen: http://www.sqlmag.com/Articles/ArticleID/9148/pg/2/2.html


4
Es gibt eine solche "Magic Global Setting"; SET ARITHABORT OFF.
David Manheim

3

Hier ist eine Situation, in der Sie durch Null teilen können. Die Geschäftsregel lautet, dass Sie zur Berechnung der Lagerumschläge die Kosten der für einen bestimmten Zeitraum verkauften Waren auf Jahresbasis berechnen. Nachdem Sie die annualisierte Zahl haben, dividieren Sie durch den durchschnittlichen Bestand für den Zeitraum.

Ich möchte die Anzahl der Inventarumdrehungen berechnen, die in einem Zeitraum von drei Monaten stattfinden. Ich habe berechnet, dass ich die Kosten für Waren innerhalb des Dreimonatszeitraums von 1.000 USD verkauft habe. Die jährliche Umsatzrate beträgt 4.000 USD (1.000 USD / 3) * 12. Das Anfangsinventar ist 0. Das Endinventar ist 0. Mein durchschnittliches Inventar ist jetzt 0. Ich habe einen Umsatz von 4000 USD pro Jahr und kein Inventar. Dies ergibt eine unendliche Anzahl von Windungen. Dies bedeutet, dass mein gesamtes Inventar von Kunden konvertiert und gekauft wird.

Dies ist eine Geschäftsregel für die Berechnung von Lagerumschlägen.


3
Ja, Sie haben dann unendlich viele Umdrehungen. Wenn Sie in diesem Fall eine Division durch Null haben, sollten Sie so etwas wie '#INF' anzeigen.
SQL Police

1
"Das Anfangsinventar ist 0. Das Endinventar ist 0. Mein durchschnittliches Inventar ist jetzt 0." Ihre Berechnung ist eine Schätzung. Irgendwann ist der Lagerbestand positiv oder Sie können nichts versenden / verkaufen. Wenn Sie mit + ∞ nicht zufrieden sind, verwenden Sie eine bessere Schätzung des durchschnittlichen Lagerbestands.
Tom Blodget

2
CREATE FUNCTION dbo.Divide(@Numerator Real, @Denominator Real)
RETURNS Real AS
/*
Purpose:      Handle Division by Zero errors
Description:  User Defined Scalar Function
Parameter(s): @Numerator and @Denominator

Test it:

SELECT 'Numerator = 0' Division, dbo.fn_CORP_Divide(0,16) Results
UNION ALL
SELECT 'Denominator = 0', dbo.fn_CORP_Divide(16,0)
UNION ALL
SELECT 'Numerator is NULL', dbo.fn_CORP_Divide(NULL,16)
UNION ALL
SELECT 'Denominator is NULL', dbo.fn_CORP_Divide(16,NULL)
UNION ALL
SELECT 'Numerator & Denominator is NULL', dbo.fn_CORP_Divide(NULL,NULL)
UNION ALL
SELECT 'Numerator & Denominator = 0', dbo.fn_CORP_Divide(0,0)
UNION ALL
SELECT '16 / 4', dbo.fn_CORP_Divide(16,4)
UNION ALL
SELECT '16 / 3', dbo.fn_CORP_Divide(16,3)

*/
BEGIN
    RETURN
        CASE WHEN @Denominator = 0 THEN
            NULL
        ELSE
            @Numerator / @Denominator
        END
END
GO

Ihre Lösung gefällt mir nicht, da die Verwendung einer UDF die Ausführung der Abfrage in einem einzelnen Thread-Modus erzwingt. Ich mag dein Test-Setup. Das hätte ich gerne in all unseren UDFs.
Henrik Staun Poulsen

Für mich ist diese Lösung perfekt und elegant
Payedimaunt

@Payedimaunt; Ja, UDFs führen zu sehr elegantem Code. Aber es funktioniert nicht gut. Dies ist "Cursor auf Schlaftabletten". :-) Es ist auch schwierig, sich daran zu erinnern, dbo zu schreiben. Teilen statt eines gewöhnlichen "/"
Henrik Staun Poulsen

1

Filtern Sie Daten mithilfe einer where-Klausel heraus, damit Sie keine 0-Werte erhalten.


1

Manchmal ist 0 möglicherweise nicht geeignet, aber manchmal ist 1 auch nicht geeignet. Manchmal kann auch ein Sprung von 0 auf 100.000.000, der als 1 oder 100-prozentige Änderung beschrieben wird, irreführend sein. In diesem Szenario könnten 100.000.000 Prozent angemessen sein. Es hängt davon ab, welche Art von Schlussfolgerungen Sie aufgrund der Prozentsätze oder Verhältnisse ziehen möchten.

Zum Beispiel kann ein sehr kleinverkaufter Artikel, der von 2-4 verkauft wird, und ein sehr großverkaufter Artikel, der von 1.000.000 auf 2.000.000 verkauft wird, für einen Analysten oder das Management sehr unterschiedliche Bedeutungen haben, aber beide werden zu 100% oder 1 durchkommen Veränderung.

Es ist möglicherweise einfacher, NULL-Werte zu isolieren, als eine Reihe von 0% - oder 100% -Zeilen zu durchsuchen, die mit legitimen Daten gemischt sind. Oft kann eine 0 im Nenner auf einen Fehler oder einen fehlenden Wert hinweisen, und Sie möchten möglicherweise nicht nur einen beliebigen Wert eingeben, damit Ihr Datensatz ordentlich aussieht.

CASE
     WHEN [Denominator] = 0
     THEN NULL --or any value or sub case
     ELSE [Numerator]/[Denominator]
END as DivisionProblem

1
Ich finde, dass das Problem darin besteht, sich daran zu erinnern, etwas zu tun, wann immer Sie eine Teilung durchführen möchten. Wenn Sie sich nicht daran erinnern, CASE oder NULLIF hinzugefügt zu haben, erhalten Sie in x Wochen an einem Montagmorgen einen Support-Fall. Ich hasse, dass.
Henrik Staun Poulsen

1

So habe ich es behoben:

IIF (WertA! = 0, Gesamt / WertA, 0)

Es kann in ein Update eingeschlossen werden:

SET Pct = IIF (WertA! = 0, Gesamt / WertA, 0)

Oder in einer Auswahl:

SELECT IIF (WertA! = 0, Gesamt / WertA, 0) AS Pct FROM Tablename;

Gedanken?


Ich und andere finden, dass das Ersetzen von "unbekannt" durch Null eine gefährliche Lösung ist. Ich bevorzuge NULL. Das Schwierige ist jedoch, sich daran zu erinnern, in allen Abteilungen iif oder nullif hinzuzufügen!
Henrik Staun Poulsen

0

Sie können den Fehler entsprechend behandeln, wenn er an das aufrufende Programm zurückgegeben wird (oder ihn ignorieren, wenn Sie dies wünschen). In C # lösen alle Fehler, die in SQL auftreten, eine Ausnahme aus, die ich abfangen und dann in meinem Code behandeln kann, genau wie jeder andere Fehler.

Ich stimme Beska darin zu, dass Sie den Fehler nicht verbergen möchten. Möglicherweise haben Sie es nicht mit einem Kernreaktor zu tun, aber das Ausblenden von Fehlern im Allgemeinen ist eine schlechte Programmierpraxis. Dies ist einer der Gründe, warum die meisten modernen Programmiersprachen eine strukturierte Ausnahmebehandlung implementieren, um den tatsächlichen Rückgabewert mit einem Fehler- / Statuscode zu entkoppeln. Dies gilt insbesondere, wenn Sie Mathe machen. Das größte Problem ist, dass Sie nicht zwischen einer korrekt berechneten 0, die zurückgegeben wird, oder einer 0 als Ergebnis eines Fehlers unterscheiden können. Stattdessen ist jeder zurückgegebene Wert der berechnete Wert. Wenn etwas schief geht, wird eine Ausnahme ausgelöst. Dies hängt natürlich davon ab, wie Sie auf die Datenbank zugreifen und welche Sprache Sie verwenden. Sie sollten jedoch immer in der Lage sein, eine Fehlermeldung zu erhalten, mit der Sie umgehen können.

try
{
    Database.ComputePercentage();
}
catch (SqlException e)
{
    // now you can handle the exception or at least log that the exception was thrown if you choose not to handle it
    // Exception Details: System.Data.SqlClient.SqlException: Divide by zero error encountered.
}

1
Ich denke, wir sind uns alle einig, dass es keine Lösung ist, den Fehler mit einer 0 zu verbergen. Ich schlage vor, unseren Code so zu schreiben, dass auf jedes "/" ein "NULLIF" folgt. Auf diese Weise wird mein Bericht / Kernreaktor nicht alleine gelassen, sondern zeigt einen "NULL" anstelle dieses lästigen Fehlers Msg 8134. Wenn ich einen anderen Prozess benötige, wenn der Divisor 0 ist, sind Beska und ich uns einig. Wir müssen das codieren. Es ist nur schwierig, jedes Mal ein "/" zu schreiben. "/ NULLIF" ist nicht jedes Mal unmöglich.
Henrik Staun Poulsen

0

Verwenden Sie NULLIF(exp,0)aber auf diese Weise -NULLIF(ISNULL(exp,0),0)

NULLIF(exp,0)bricht, wenn exp ist, nullaber NULLIF(ISNULL(exp,0),0)nicht brechen wird


1
Ich kann NULLIF (exp, 0) nicht erhalten, wenn 0 eine Null ist, kein o. Versuchen; DECLARE @i INT SELECT 1 / NULLIF (@i, 0), um zu sehen, ob Sie es zum Brechen bringen können.
Henrik Staun Poulsen
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.