PostgreSQL usando count () para determinar porcentagens (problemas de conversão)

19

Estou tentando executar a seguinte consulta para fornecer a% de linhas na minha patientstabela que possuem um valor na refinstcoluna. Eu continuo recebendo um resultado de 0.

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

A tabela possui 15556 linhas e select count(refinst) from patientsinforma que 1446 delas possuem um valor na refinstcoluna. A resposta que gostaria de obter da consulta seria 30,62 ( 1446/15556*100=30.62XXXXX, arredondada para duas casas decimais).

Tenho certeza de que tem algo a ver com o tipo de dados dos resultados da contagem (números inteiros, estou assumindo). Se eu dividir um número inteiro por um número inteiro e o resultado for menor que 0, ele será truncado para 0 correto? Se for esse o caso, alguém pode me mostrar como converter os resultados das contagens como um número com 2 casas decimais, para que o resultado também seja arredondado para 2 casas decimais?

Tenho certeza de que há uma maneira melhor de escrever esse código do que várias instruções de contagem. Estou procurando uma maneira mais eficiente do processador para escrever essa consulta em particular.

user3779117
fonte
Talvez essa resposta possa ajudá-lo.
Jhon Anderson Cardenas Díaz

Respostas:

26
SELECT (count(refinst) * 100)::numeric / count(*) AS refinst_percentage
FROM   patients;
  • Você não usar um subselect. Ambos os agregados podem ser derivados da mesma consulta. Mais barato.

  • Além disso, esse não é o caso das funções da janela, pois você deseja calcular um único resultado e não um resultado por linha.

  • Transmitir para qualquer tipo numérico que suporte dígitos fracionários, como @a_horse já explicado .
    Como você deseja round()dois dígitos fracionários, sugiro numeric(que é o mesmo que decimalno Postgres).
    Mas basta lançar um valor envolvido em um cálculo, de preferência o primeiro. O Postgres aceita automaticamente o tipo que não perde informações.

  • Geralmente, é uma boa ideia multiplicar antes de dividir . Isso geralmente minimiza os erros de arredondamento e é mais barato.
    Nesse caso, a primeira multiplicação ( count(refinst) * 100) pode ser calculada com integeraritmética barata e exata . Só então nós escalado para numerice dividir pelo lado integer(que nós não lançar adicionalmente).

Arredondado para dois dígitos fracionários:

SELECT round((count(refinst) * 100)::numeric / count(*), 2) AS refinst_percentage
FROM   patients;
Erwin Brandstetter
fonte
Claro que você está certo, a função de janela não é necessária. Mas isso realmente não faz diferença (além da legibilidade).
a_horse_with_no_name 26/06
3

Você precisa converter cada número envolvido na divisão em um tipo que suporte decimais:

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

Você também pode tentar uma função de janela em vez da subconsulta escalar. Pode ser mais rápido:

select (count(refinst)::decimal / (count(*) over ())::decimal) * 100 as "Formula" 
from patients;
um cavalo sem nome
fonte
0

Sei que esse segmento tem alguns anos, mas: tente multiplicar por 100,0 em vez de 100 Isso deve converter automaticamente o resultado como um float em vez de um número inteiro.

Alan McGill
fonte