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

192

Я использую 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

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

user1626730
источник
3
Ваше сообщение об ошибке не соответствует коду в вашем вопросе.
Му слишком коротка
Помимо синтаксической ошибки, этот тесно связанный вопрос о dba.SE проливает свет на округление чисел с двойной точностью в PostgreSQL.
Эрвин Брандштеттер
@muistooshort, спасибо за указание на это. Он должен сказать «круглый», где он говорит «в среднем». Ред.
user1626730
ради результатов поиска я также получаю эту подсказку как вывод из приглашения:HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Vzzarr

Ответы:

266

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что вы не хотите отступов с ведущими пробелами.

Крейг Рингер
источник
Хм. Когда я пробую ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, я получаю «0.314E1». И мой код написан, ROUND(AVG(val),2)но я все еще получаю ошибку, описанную в моем вопросе.
user1626730
Я просто бегал ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);на PgAdmin и Ruby. С PgAdmin я получаю 3.14, но с Ruby (используя гем Sequel) я получаю 0.314E1. Интересно, почему это ...
user1626730
12
«По какой-то странной причине версия раунда, которая принимает точность, доступна только для числовых». Числа с плавающей точкой являются «полезными приближениями». Если вы попросите код округлить число с плавающей запятой до двух десятичных разрядов, возвращая другое число с плавающей запятой, нет гарантии, что ближайшее приближение к «правильному» ответу будет иметь только две цифры справа от десятичного знака. Числа эффективно масштабируются целыми числами; у них нет этой проблемы.
Майк Шеррилл 'Cat Recall'
@Catcall Хорошее замечание - doubleверсию roundнужно будет вернуть numericили (тьфу) text, поэтому она может также принять numericаргумент.
Крейг Рингер
6
Для тех, кто пытается найти комментарий @Catcall: теперь это Mike Sherrill 'Cat Recall'
18446744073709551615
90

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

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после перегрузок, покажет что-то вроде,

Схема | Имя | Тип данных результата | Типы данных аргумента
------------ + ------- + ------------------ + ---------- ------------------
 Мыщема круглый | двойная точность | двойная точность, текст, int
 Мыщема круглый | числовой | двойная точность, int
 pg_catalog | круглый | двойная точность | двойная точность            
 pg_catalog | круглый | числовой | числовой   
 pg_catalog | круглый | числовой | числовой, int          

Эти pg_catalogфункции являются те , по умолчанию, см руководство по сборке-математических функций .

Питер Краусс
источник
38

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

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

Или просто:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
atiruz
источник
5
Я считаю, что это будет гораздо более кратким и непосредственным шагом вперед с моим дневным ответом на этот вопрос. : bow:
craastad
2
Тоже самое! Очень короткое и полезное решение.
Алексей Шабрамов
7

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

 SELECT TRUNC(14.568,2);

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

14.56

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

 SELECT TRUNC(YOUR_VAR::numeric,2)
AdagioDev
источник
3

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

select date,(wind_speed/3.6)::numeric(7,1) from readings;
kometen
источник
2

Попробуйте привести ваш столбец к числовому типу:

SELECT ROUND(cast(some_column as numeric),2) FROM table
Габриэль Хайме Сьерра Руа
источник
1

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

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

Пример: round(extract(second from job_end_time_t)::integer,0)

user5702982
источник
0

выберите ROUND (SUM (сумма) :: числовой, 2) в качестве total_amount FROM транзакций

т: 200234.08

vlatko606
источник