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.

William Wino
quelle
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.

Erwin Brandstetter
quelle
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

Yuriy Galanter
quelle
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.

vol7ron
quelle
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;
Manvel
quelle
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.

Clodoaldo Neto
quelle
Netter Trick, aber ich denke, dass eine Fallaussage offensichtlicher sein könnte.
David Aldridge
CASEist auch schneller, auch wenn ausführlicher.
Erwin Brandstetter