Как округлить среднее значение до 2 знаков после запятой в PostgreSQL?

Я использую PostgreSQL через сиквел Ruby gem.

Я пытаюсь округлить до двух десятичных знаков.

Вот мой код:

SELECT ROUND(AVG(some_column),2)    
FROM table

Я получаю следующую ошибку:

PG::Error: ERROR:  function round(double precision, integer) does 
not exist (Sequel::DatabaseError)

Я не получаю ошибки при запуске следующего кода:

SELECT ROUND(AVG(some_column))
FROM table

Кто-нибудь знает, что я делаю не так?


person user1626730    schedule 28.10.2012    source источник
comment
Ваше сообщение об ошибке не соответствует коду вашего вопроса.   -  person mu is too short    schedule 29.10.2012
comment
Помимо синтаксической ошибки, этот тесно связанный вопрос о dba.SE проливает свет на округление чисел двойной точности в PostgreSQL.   -  person Erwin Brandstetter    schedule 29.10.2012
comment
@muistooshort, Спасибо, что указали на это. В нем должно быть написано «круглое» вместо «средн.». Отредактировано.   -  person user1626730    schedule 29.10.2012
comment
ради результатов поиска я также получаю эту подсказку в виде вывода из приглашения: HINT: No function matches the given name and argument types. You might need to add explicit type casts.   -  person Vzzarr    schedule 21.04.2020


Ответы (8)


PostgreSQL не определяет round(double precision, integer). По причинам, которые @Mike Sherrill 'Cat Recall' объясняет в комментариях, версия раунда, требующая точности, доступна только для numeric.

regress=> SELECT round( float8 '3.1415927', 2 );
ERROR:  function round(double precision, integer) does not exist

regress=> \df *round*
                           List of functions
   Schema   |  Name  | Result data type | Argument data types |  Type  
------------+--------+------------------+---------------------+--------
 pg_catalog | dround | double precision | double precision    | normal
 pg_catalog | round  | double precision | double precision    | normal
 pg_catalog | round  | numeric          | numeric             | normal
 pg_catalog | round  | numeric          | numeric, integer    | normal
(4 rows)

regress=> SELECT round( CAST(float8 '3.1415927' as numeric), 2);
 round 
-------
  3.14
(1 row)

(Обратите внимание, что float8 - это просто сокращенный псевдоним для double precision. Вы можете видеть, что PostgreSQL расширяет его в выводе).

Вы должны привести значение, которое нужно округлить до numeric, чтобы использовать форму round с двумя аргументами. Просто добавьте ::numeric для сокращенного преобразования, например round(val::numeric,2).


Если вы форматируете для отображения пользователю, не используйте round. Используйте to_char (см. функции форматирования типов данных в руководстве) , который позволяет указать формат и дает результат text, не зависящий от странностей, которые ваш клиентский язык может сделать со значениями numeric. Например:

regress=> SELECT to_char(float8 '3.1415927', 'FM999999999.00');
    to_char    
---------------
 3.14
(1 row)

to_char округляет числа за вас как часть форматирования. Префикс FM сообщает to_char, что вам не нужны заполнители с ведущими пробелами.

person Craig Ringer    schedule 28.10.2012
comment
Хм. Когда я пробую ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, я получаю «0,314E1». И у меня есть код, написанный как ROUND(AVG(val),2), но я все еще получаю ошибку, описанную в моем вопросе. - person user1626730; 29.10.2012
comment
Я только что запустил ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2); на PgAdmin и Ruby. С PgAdmin я получаю 3,14, но с Ruby (используя гем Sequel) я получаю «0,314E1». Интересно, почему это ... - person user1626730; 29.10.2012
comment
По какой-то странной причине версия округления, требующая точности, доступна только для числовых значений. Числа с плавающей запятой являются полезными приближениями. Если вы попросите код округлить число с плавающей запятой до двух десятичных знаков, возвращая другое число с плавающей запятой, нет гарантии, что наиболее близкое приближение к правильному ответу будет иметь только две цифры справа от десятичный. Числа - это эффективно масштабированные целые числа; у них нет этой проблемы. - person Mike Sherrill 'Cat Recall'; 29.10.2012
comment
@Catcall Хороший момент - double версия round должна будет возвращать numeric или (тьфу) text, поэтому она может также принимать аргумент numeric. - person Craig Ringer; 29.10.2012
comment
@ user1626730 Ruby или pg драгоценный камень Ruby должен делать странные вещи со значениями numeric. Вы форматируете его для отображения пользователю? Если да, см. Обновленный ответ. - person Craig Ringer; 29.10.2012
comment
@ user1626730 Если вы по-прежнему видите ошибку после преобразования в числовое значение, покажите свой настоящий код. - person Craig Ringer; 29.10.2012
comment
@CraigRinger Похоже, драгоценный камень творит странные вещи. Однако ваш код TO_CHAR работал. Результат имеет пустые места в начале, но я могу убрать их с помощью Ruby. - person user1626730; 29.10.2012
comment
@ user1626730 Согласно документации, если вы не хотите, чтобы заполнение для знака использовалось, используйте версию FM, например SELECT to_char(float8 '3.1415927', 'FM999999999.00'). Ответ изменен. - person Craig Ringer; 30.10.2012
comment
Для тех, кто пытается найти комментарий @Catcall: теперь это Майк Шерилл 'Cat Recall' - person 18446744073709551615; 07.04.2016

Попробуйте также старый синтаксис приведения типов,

SELECT ROUND(AVG(some_column)::numeric,2)    
FROM table;

работает с любой версией PostgreSQL.

Отсутствие перегрузок в некоторых функциях PostgreSQL, почему (???): Я думаю, что это недостаток (!), но @CraigRinger, @Catcall и команда PostgreSQL согласны с историческим обоснованием pg .

PS: еще один момент, связанный с округлением, - это точность, проверьте ответ @ IanKenney.


Перегрузка как стратегия приведения

Вы можете перегрузить функцию ROUND с помощью,

 CREATE FUNCTION ROUND(float,int) RETURNS NUMERIC AS $$
    SELECT ROUND($1::numeric,$2);
 $$ language SQL IMMUTABLE;

Теперь ваша инструкция будет работать нормально, попробуйте (после создания функции)

 SELECT round(1/3.,4); -- 0.3333 numeric

но он возвращает тип NUMERIC ... Чтобы сохранить первую перегрузку использования commom, мы можем вернуть тип FLOAT, когда предлагается параметр TEXT,

 CREATE FUNCTION ROUND(float, text, int DEFAULT 0) 
 RETURNS FLOAT AS $$
    SELECT CASE WHEN $2='dec'
                THEN ROUND($1::numeric,$3)::float
                -- ... WHEN $2='hex' THEN ... WHEN $2='bin' THEN... complete!
                ELSE 'NaN'::float  -- like an error message 
            END;
 $$ language SQL IMMUTABLE;

Пытаться

 SELECT round(1/3.,'dec',4);   -- 0.3333 float!
 SELECT round(2.8+1/3.,'dec',1); -- 3.1 float!
 SELECT round(2.8+1/3.,'dec'::text); -- need to cast string? pg bug 

PS: проверка \df round после перегрузок покажет что-то вроде,

 Schema     |  Name | Result data type | Argument data types 
------------+-------+------------------+----------------------------
 myschema   | round | double precision | double precision, text, int
 myschema   | round | numeric          | double precision, int
 pg_catalog | round | double precision | double precision            
 pg_catalog | round | numeric          | numeric   
 pg_catalog | round | numeric          | numeric, int          

Функции pg_catalog являются функциями по умолчанию, см. руководство по встроенным математическим функциям < / а>.

person Peter Krauss    schedule 05.01.2014

Попробуйте с этим:

SELECT to_char (2/3::float, 'FM999999990.00');
-- RESULT: 0.67

Или просто:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
person atiruz    schedule 25.05.2016
comment
Я считаю, что это гораздо более лаконичный и прямой путь к моему дневному ответу на этот вопрос. :поклон: - person craastad; 02.03.2018
comment
То же самое! Очень короткое и полезное решение. - person Alexey Shabramov; 03.07.2019

вы можете использовать функцию ниже

 SELECT TRUNC(14.568,2);

результат покажет:

14.56

вы также можете привести свою переменную к желаемому типу:

 SELECT TRUNC(YOUR_VAR::numeric,2)
person AdagioDev    schedule 10.06.2019

Попробуйте преобразовать столбец в числовое значение, например:

SELECT ROUND(cast(some_column as numeric),2) FROM table
person Gabriel Jaime Sierra Rua    schedule 10.12.2019
comment
работа в pg10 без приведения с числовыми значениями. - person Sergio Belevskij; 14.08.2020

SELECT ROUND(SUM(amount)::numeric, 2) AS total_amount
FROM transactions

Дает: 200234.08

person vlatko606    schedule 21.05.2020

Согласно ответу Брайана, вы можете сделать это, чтобы ограничить десятичные дроби в запросе. Я конвертирую из км / ч в м / с и отображаю это в диграфах, но когда я делал это в диграфах, это выглядело странно. Выглядит нормально, когда вместо этого выполняются вычисления в запросе. Это на postgresql 9.5.1.

select date,(wind_speed/3.6)::numeric(7,1) from readings;
person kometen    schedule 20.02.2016

Ошибка: функция round (двойная точность, целое число) не существует

Решение: вам нужно добавить приведение типов, и все будет работать

Ex: round(extract(second from job_end_time_t)::integer,0)

person user5702982    schedule 21.12.2015