PostgreSQL za pomocą count () do określenia wartości procentowych (problemy z rzutowaniem)

19

Próbuję uruchomić następujące zapytanie, aby podać% wierszy w mojej patientstabeli, które mają wartość refinstkolumny. Ciągle otrzymuję wynik 0.

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

Tabela ma 15556 wierszy i select count(refinst) from patientsmówi mi, że 1446 z nich ma wartość w refinstkolumnie. Odpowiedź, którą chciałbym uzyskać z zapytania, wynosiłaby 30,62 ( 1446/15556*100=30.62XXXXXw zaokrągleniu do dwóch miejsc po przecinku).

Jestem pewien, że ma to coś wspólnego z typem danych wyników zliczania (zakładam, że liczby całkowite). Jeśli podzielę liczbę całkowitą przez liczbę całkowitą, a wynik jest mniejszy niż 0, to zostanie obcięty do 0, prawda? Jeśli tak jest, czy ktoś może mi pokazać, jak rzutować wyniki liczenia jako liczbę z 2 miejscami po przecinku, aby wynik również został zaokrąglony do 2 miejsc po przecinku?

Jestem pewien, że istnieje lepszy sposób na napisanie tego kodu niż wiele instrukcji zliczania. Szukam w szczególności bardziej wydajnego sposobu na napisanie tego zapytania.

użytkownik3779117
źródło
Może ta odpowiedź może ci pomóc.
Jhon Anderson Cardenas Diaz

Odpowiedzi:

26
SELECT (count(refinst) * 100)::numeric / count(*) AS refinst_percentage
FROM   patients;
  • Czy nie używać podselekcji. Oba agregaty można wyprowadzić z tego samego zapytania. Taniej.

  • Ponadto, jest to nie sprawa dla funkcji okna, ponieważ chcesz obliczyć pojedynczy wynik, a nie jeden wynik w każdym wierszu.

  • Przesyłaj na dowolny typ liczbowy, który obsługuje cyfry ułamkowe, jak już wyjaśniono @a_horse .
    Ponieważ chcesz round()użyć dwóch cyfr ułamkowych, sugeruję numeric(to samo co decimalw Postgresie).
    Ale wystarczy rzucić jedną wartość uwzględnioną w obliczeniach, najlepiej pierwszą. Postgres automatycznie ustala typ, który nie powoduje utraty informacji.

  • Na ogół dobrym pomysłem jest pomnożenie przed podzieleniem . Zwykle minimalizuje to błędy zaokrąglania i jest tańsze.
    W takim przypadku pierwsze mnożenie ( count(refinst) * 100) można obliczyć za pomocą taniej i dokładnej integerarytmetyki. Dopiero wtedy rzucamy numerici dzielimy przez kolejnych integer(których nie rzucamy dodatkowo).

Zaokrąglone do dwóch cyfr ułamkowych:

SELECT round((count(refinst) * 100)::numeric / count(*), 2) AS refinst_percentage
FROM   patients;
Erwin Brandstetter
źródło
Oczywiście masz rację, funkcja okna nie jest potrzebna. Ale to tak naprawdę nie robi różnicy (oprócz czytelności).
a_horse_w___nazwa
3

Musisz rzucić każdą liczbę uczestniczącą w podziale na typ, który obsługuje liczby dziesiętne:

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

Możesz także wypróbować funkcję okna zamiast podskalarnego zapytania. Może być szybciej:

select (count(refinst)::decimal / (count(*) over ())::decimal) * 100 as "Formula" 
from patients;
koń bez imienia
źródło
0

Zdaję sobie sprawę, że ten wątek ma kilka lat, ale: spróbuj pomnożyć przez 100,0 zamiast przez 100, co powinno automatycznie rzutować wynik jako liczbę zmiennoprzecinkową, a nie liczbę całkowitą.

Alan McGill
źródło