Vermeiden Sie die Division durch Null in PostgreSQL


76

Ich möchte eine Division in einer SELECT-Klausel durchführen. Wenn ich einige Tabellen verbinde und die Aggregatfunktion verwende, habe ich oft entweder Null- oder Nullwerte als Teiler. Im Moment habe ich nur diese Methode entwickelt, um die Division durch Null- und Nullwerte zu vermeiden.

(CASE(COALESCE(COUNT(column_name),1)) WHEN 0 THEN 1
ELSE (COALESCE(COUNT(column_name),1)) END) 

Ich frage mich, ob es einen besseren Weg gibt, dies zu tun.


4
Die Division durch einen Nullwert ist kein Problem wie die Division durch Null. Count () gibt übrigens nie null zurück.
David Aldridge

Das wusste ich nicht! Danke für die Information.
William Wino

Antworten:


41

Da count()nie zurückgegeben wirdNULL (im Gegensatz zu anderen Aggregatfunktionen), müssen Sie nur den 0Fall erfassen (was ohnehin der einzige problematische Fall ist):

CASE count(column_name)
   WHEN 0 THEN 1
   ELSE count(column_name)
END

Zitieren des Handbuchs zu Aggregatfunktionen:

Es ist zu beachten, dass countdiese Funktionen mit Ausnahme von einen Nullwert zurückgeben, wenn keine Zeilen ausgewählt sind.


215

Sie können die NULLIF- Funktion verwenden, z

something/NULLIF(column_name,0)

Wenn der Wert von column_name0 ist, ist das Ergebnis des gesamten Ausdrucks NULL


14
so etwas wie value / COALESCE (NULLIF (Spaltenname, 0), 1) würde funktionieren, nehme ich an
Akash

Versuchte es mit COALESCE als @Akash vorgeschlagen und es hat die Arbeit
abd

3
Dies ist die perfekt semantische Lösung für viele Probleme durch Division durch Null! Manchmal möchten Sie nicht, dass die Division ein anderer Wert ist, sondern dass sie überhaupt nicht berechnet wird!
LeoRochael

38

Mir ist klar, dass dies eine alte Frage ist, aber eine andere Lösung wäre, die größte Funktion zu nutzen:

greatest( count(column_name), 1 )  -- NULL and 0 are valid argument values

Hinweis: Ich würde es vorziehen, entweder eine NULL zurückzugeben, wie in der Antwort von Erwin und Yuriy, oder dies logisch zu lösen, indem der Wert 0vor der Divisionsoperation erkannt und zurückgegeben wird 0. Andernfalls können die Daten durch die Verwendung falsch dargestellt werden 1.


Ich werde dies verwenden, da mein Divisor eine "verstrichene Zeit" für einen Prozess ist und 0 wahrscheinlich einen Bruchteil einer Sekunde bedeutet, also werde ich 0,01 Minuten als Standardzeit verwenden. Ich vergleiche nur die Prozessleistung.
PhilHibbs

Dies war die einfachste Lösung für mich in Bezug auf die Lesbarkeit
Florent Destremau

4

Eine andere Lösung, die die Division durch Null vermeidet und durch 1 ersetzt

select column + (column = 0)::integer;

Das ist wirklich klug.
Lightyrs

3

Wenn Sie möchten, dass der Teiler 1 ist, wenn die Anzahl Null ist:

count(column_name) + 1 * (count(column_name) = 0)::integer

Die Besetzung von truebis integerist 1.


Netter Trick, aber ich denke, dass eine Fallaussage offensichtlicher sein könnte.
David Aldridge

CASEist auch schneller, auch wenn ausführlicher.
Erwin Brandstetter
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.