PostgreSQL verwendet count (), um Prozentsätze zu bestimmen (Besetzungsprobleme)


19

Ich versuche, die folgende Abfrage auszuführen, um den Prozentsatz der Zeilen in meiner patientsTabelle anzugeben, die einen Wert für die refinstSpalte haben. Ich bekomme immer ein Ergebnis von 0.

select (count (refinst) / (select count(*) from patients) * 100) as "Formula" 
from patients;

Die Tabelle enthält 15556 Zeilen. Davon select count(refinst) from patientshaben 1446 einen Wert in der refinstSpalte. Die Antwort, die ich von der Abfrage erhalten möchte, wäre 30,62 ( 1446/15556*100=30.62XXXXXauf zwei Dezimalstellen gerundet).

Ich bin mir ziemlich sicher, dass es etwas mit dem Datentyp der Zählergebnisse zu tun hat (Ganzzahlen nehme ich an). Wenn ich eine Ganzzahl durch eine Ganzzahl dividiere und das Ergebnis kleiner als 0 ist, wird es auf 0 abgeschnitten, richtig? Wenn dies der Fall ist, kann mir jemand zeigen, wie ich die Ergebnisse der Zählungen als Zahl mit 2 Dezimalstellen ausgeben kann, sodass das Ergebnis ebenfalls auf 2 Dezimalstellen gerundet wird?

Ich bin mir sicher, dass es einen besseren Weg gibt, diesen Code zu schreiben, als mehrere count-Anweisungen. Ich bin auf der Suche nach einer prozessoreffizienteren Methode, um diese Abfrage zu schreiben.


Vielleicht hilft Ihnen diese Antwort .
Jhon Anderson Cardenas Diaz

Antworten:


26
SELECT (count(refinst) * 100)::numeric / count(*) AS refinst_percentage
FROM   patients;
  • Verwenden Sie keine Unterauswahl. Beide Aggregate können aus derselben Abfrage abgeleitet werden. Billiger.

  • Dies gilt auch nicht für Fensterfunktionen, da Sie ein einzelnes Ergebnis und nicht ein Ergebnis pro Zeile berechnen möchten.

  • Umwandlung in einen beliebigen numerischen Typ , der Nachkommastellen unterstützt, wie @a_horse bereits erläutert .
    Da du round()zwei Nachkommastellen haben willst schlage ich vor numeric(das ist das gleiche wie decimalbei Postgres).
    Es reicht jedoch aus, einen an einer Berechnung beteiligten Wert zu setzen, vorzugsweise den ersten. Postgres stellt sich automatisch auf den Typ ein, bei dem keine Informationen verloren gehen.

  • Es ist im Allgemeinen eine gute Idee, vor der Teilung zu multiplizieren . Dies minimiert typischerweise Rundungsfehler und ist billiger.
    In diesem Fall kann die erste Multiplikation ( count(refinst) * 100) mit billiger und genauer integerArithmetik berechnet werden . Erst dann werfen wir nach numericund teilen durch die nächsten integer(die wir nicht zusätzlich werfen).

Auf zwei Nachkommastellen gerundet:

SELECT round((count(refinst) * 100)::numeric / count(*), 2) AS refinst_percentage
FROM   patients;

Natürlich haben Sie recht, die Fensterfunktion wird nicht benötigt. Aber dann macht es keinen großen Unterschied (abgesehen von der Lesbarkeit).
a_horse_with_no_name

3

Sie müssen jede Zahl, die an der Division beteiligt ist, in einen Typ umwandeln, der Dezimalstellen unterstützt:

select (count(refinst)::decimal / (select count(*) from patients)::decimal) * 100  as "Formula" 
from patients;

Möglicherweise möchten Sie auch eine Fensterfunktion anstelle der skalaren Unterabfrage ausprobieren. Es könnte schneller sein:

select (count(refinst)::decimal / (count(*) over ())::decimal) * 100 as "Formula" 
from patients;

0

Mir ist klar, dass dieser Thread ein paar Jahre alt ist, aber: versuchen Sie es mit 100.0 anstatt mit 100. Das sollte das Ergebnis automatisch als Float und nicht als Integer ausgeben.

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.