PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Calcular porcentagens de SUM() na mesma consulta SQL SELECT


Há mais nesta pergunta do que parece.

Versão simples


Isso é muito mais rápido e simples:
SELECT property_name
      ,(count(value_a = value_b OR NULL) * 100) / count(*) AS pct
FROM   my_obj
GROUP  BY 1;

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

Como?

  • Você não precisa de uma função para isso.

  • Em vez de contar value_b (que você não precisa para começar) e calcular o total, use count(*) para o total. Mais rápido, mais simples.

  • Isso pressupõe que você não tenha NULL valores. Ou seja ambas as colunas são definidas NOT NULL . As informações estão faltando na sua pergunta.
    Caso contrário, sua consulta original provavelmente não está fazendo o que você acha que faz . Se algum dos valores for NULL, sua versão não contará essa linha. Você pode até provocar uma divisão por zero exceção desta forma.
    Esta versão também funciona com NULL. count(*) produz a contagem de todas as linhas, independentemente dos valores.

  • Veja como funciona a contagem:
     TRUE  OR NULL = TRUE
     FALSE OR NULL = NULL
    

    count() ignora valores NULL. Voilá.

  • A precedência do operador rege que = vincula antes de OR . Você pode adicionar parênteses para deixar mais claro:
    count ((value_a = value_b) OR FALSE)
    

  • Você pode fazer o mesmo com
    count NULLIF(<expression>, FALSE)
    

  • O tipo de resultado de count() é bigint por padrão.
    Uma divisão bigint / bigint , trunca dígitos fracionários .

Incluir dígitos fracionários


Use 100.0 (com dígito fracionário) para forçar o cálculo a ser numeric e assim preservar dígitos fracionários.
Você pode querer usar round() com isso:
SELECT property_name
      ,round((count(value_a = value_b OR NULL) * 100.0) / count(*), 2) AS pct
FROM   my_obj
GROUP  BY 1;

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

Como um aparte:
eu uso value_a em vez de valueA . Não use identificadores de maiúsculas e minúsculas sem aspas no PostgreSQL. Tenho visto muitas perguntas desesperadas provenientes dessa loucura. Se você quer saber do que estou falando, leia o capítulo Identificadores e Palavras-Chave do manual.