PostgreSQL использует count () для определения процентов (проблемы приведения)

19

Я пытаюсь выполнить следующий запрос, чтобы обеспечить% строк в моей patientsтаблице, которые имеют значение refinstстолбца. Я продолжаю получать результат 0.

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

Таблица содержит 15556 строк и select count(refinst) from patientsсообщает, что 1446 из них имеют значение в refinstстолбце. Ответ, который я хотел бы получить от запроса, был бы 30,62 ( 1446/15556*100=30.62XXXXXокругленный до двух десятичных знаков).

Я почти уверен, что это как-то связано с типом данных результатов подсчета (я предполагаю целые числа). Если я разделю целое число на целое число, а результат будет меньше 0, он будет усечен до 0 правильно? Если это так, может кто-нибудь показать мне, как привести результаты подсчета к числу с двумя десятичными знаками, чтобы результат также округлялся до 2 десятичных знаков?

Я уверен, что есть лучший способ написать этот код, чем несколько операторов подсчета. Я ищу более эффективный для процессора способ написать этот запрос в частности.

user3779117
источник
Может быть, этот ответ может помочь вам.
Джон Андерсон Карденас Диас

Ответы:

26
SELECT (count(refinst) * 100)::numeric / count(*) AS refinst_percentage
FROM   patients;
  • Вы не использовать подзапрос. Оба агрегата могут быть получены из одного и того же запроса. Дешевле.

  • Кроме того, это не относится к оконным функциям, так как вы хотите вычислить один результат, а не один результат на строку.

  • Приведение к любому числовому типу, который поддерживает дробные цифры, как уже объяснено @a_horse .
    Так как вы хотите до round()двух дробных цифр, я предлагаю numeric(это то же самое, что и decimalв Postgres).
    Но достаточно привести одно значение, участвующее в расчете, предпочтительно первое. Postgres автоматически выбирает тип, который не теряет информацию.

  • Обычно это хорошая идея, чтобы умножить, прежде чем делить . Это обычно сводит к минимуму ошибки округления и обходится дешевле.
    В этом случае первое умножение ( count(refinst) * 100) может быть вычислено с использованием дешевой и точной integerарифметики. Только тогда мы разыгрываем numericи делим на следующие integer(которые мы не разыгрываем дополнительно).

Округлено до двух дробных цифр:

SELECT round((count(refinst) * 100)::numeric / count(*), 2) AS refinst_percentage
FROM   patients;
Эрвин Брандштеттер
источник
Конечно, вы правы, оконная функция не нужна. Но тогда это не имеет большого значения (кроме читабельности).
a_horse_with_no_name
3

Вам нужно привести каждое число, участвующее в делении, к типу, который поддерживает десятичные дроби:

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

Вы также можете попробовать оконную функцию вместо скалярного подзапроса. Это может быть быстрее:

select (count(refinst)::decimal / (count(*) over ())::decimal) * 100 as "Formula" 
from patients;
a_horse_with_no_name
источник
0

Я понимаю, что этой ветке пару лет, но: попробуйте умножить на 100,0, а не на 100. Это должно автоматически привести к результату как число с плавающей точкой, а не как целое число.

Алан МакГилл
источник