web-dev-qa-db-fra.com

PostgreSQL utilisant count () pour déterminer les pourcentages (problèmes de distribution)

J'essaie d'exécuter la requête suivante pour fournir le% de lignes de ma table patients qui ont une valeur dans la colonne refinst. J'obtiens toujours un résultat de 0.

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

La table a 15556 lignes et select count(refinst) from patients me dit que 1446 d'entre elles ont une valeur dans la colonne refinst. La réponse que j'aimerais obtenir de la requête serait 30,62 (1446/15556*100=30.62XXXXX, Arrondi à deux décimales).

Je suis presque sûr que cela a quelque chose à voir avec le type de données des résultats de comptage (entiers, je suppose). Si je divise un entier par un entier et que le résultat est inférieur à 0, il est tronqué à 0 correct? Si tel est le cas, quelqu'un peut-il me montrer comment convertir les résultats des décomptes en nombre avec 2 décimales afin que le résultat soit également arrondi à 2 décimales?

Je suis sûr qu'il existe une meilleure façon d'écrire ce code que plusieurs instructions de comptage. Je recherche en particulier un moyen plus efficace pour écrire cette requête.

20
user3779117
SELECT (count(refinst) * 100)::numeric / count(*) AS refinst_percentage
FROM   patients;
  • N'utilisez pas une sous-sélection. Les deux agrégats peuvent être dérivés de la même requête. Moins cher.

  • En outre, ce n'est pas un cas pour les fonctions de fenêtre, car vous voulez calculer un seul résultat, et non un résultat par ligne.

  • Cast à n'importe quel type numérique qui prend en charge les chiffres fractionnaires, comme @ a_horse déjà expliqué .
    Puisque vous voulez round() à deux chiffres fractionnaires, je suggère numeric (qui est identique à decimal dans Postgres).
    Mais il suffit de lancer un valeur impliquée dans un calcul, de préférence le premier. Postgres se contente automatiquement du type qui ne perd pas d'informations.

  • C'est généralement une bonne idée de multiplier avant vous divisez . Cela minimise généralement les erreurs d'arrondi et est moins cher.
    Dans ce cas, la première multiplication (count(refinst) * 100) peut être calculée avec une arithmétique exacte et bon marché integer. Seulement alors nous convertissons en numeric et divisons par le suivant integer (ce que nous faisons pas cast en plus).

Arrondi à deux chiffres fractionnaires:

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

Vous devez convertir chaque nombre impliqué dans la division en un type qui prend en charge les décimales:

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

Vous pouvez également essayer une fonction de fenêtre au lieu de la sous-requête scalaire. Cela pourrait être plus rapide:

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

Je me rends compte que ce fil a quelques années mais: essayez de multiplier par 100,0 plutôt que par 100 Cela devrait automatiquement convertir le résultat en un flottant plutôt qu'en un entier.

0
Alan McGill