PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Calculer les pourcentages à partir de SUM() dans la même requête SQL SELECT

Il y a plus à cette question qu'il n'y paraît.

Version simplifiée

C'est beaucoup plus rapide et plus simple :

SELECT property_name
      ,(count(value_a = value_b OR NULL) * 100) / count(*) AS pct
FROM   my_obj
GROUP  BY 1;

Résultat :

property_name | pct
--------------+----
 prop_1       | 17
 prop_2       | 43

Comment ?

  • Vous n'avez pas du tout besoin d'une fonction pour cela.

  • Au lieu de compter value_b (dont vous n'avez pas besoin pour commencer) et en calculant le total, utilisez count(*) pour la totalité. Plus rapide, plus simple.

  • Cela suppose que vous n'avez pas NULL valeurs. C'est à dire. les deux colonnes sont définies NOT NULL . Les informations manquent dans votre question.
    Si ce n'est pas le cas, votre requête d'origine ne fait probablement pas ce que vous pensez qu'elle fait . Si l'une des valeurs est NULL, votre version ne compte pas du tout cette ligne. Vous pourriez même provoquer une division par zéro exception de cette façon.
    Cette version fonctionne également avec NULL. count(*) produit le nombre de toutes les lignes, quelles que soient les valeurs.

  • Voici comment fonctionne le décompte :

     TRUE  OR NULL = TRUE
     FALSE OR NULL = NULL
    

    count() ignore les valeurs NULL. Voilà.

  • La priorité des opérateurs régit que = se lie avant OR . Vous pouvez ajouter des parenthèses pour le rendre plus clair :

    count ((value_a = value_b) OR FALSE)
    
  • Vous pouvez faire la même chose avec

    count NULLIF(<expression>, FALSE)
    
  • Le type de résultat de count() est bigint par défaut.
    Une division bigint / bigint , tronque les chiffres fractionnaires .

Inclure les chiffres fractionnaires

Utilisez 100.0 (avec chiffre fractionnaire) pour forcer le calcul à être numeric et ainsi préserver les chiffres fractionnaires.
Vous pouvez utiliser round() avec ceci :

SELECT property_name
      ,round((count(value_a = value_b OR NULL) * 100.0) / count(*), 2) AS pct
FROM   my_obj
GROUP  BY 1;

Résultat :

property_name | pct
--------------+-------
 prop_1       | 17.23
 prop_2       | 43.09

En aparté :
J'utilise value_a au lieu de valueA . N'utilisez pas d'identificateurs à casse mixte sans guillemets dans PostgreSQL. J'ai vu trop de questions désespérées venant de cette folie. Si vous vous demandez de quoi je parle, lisez le chapitre Identifiants et mots clés du manuel.