Como arredondar uma média para duas casas decimais no PostgreSQL?

191

Estou usando o PostgreSQL através da 'sequela' da gema Ruby.

Estou tentando arredondar para duas casas decimais.

Aqui está o meu código:

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

Estou tendo o erro a seguir:

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

Não recebo nenhum erro quando executo o seguinte código:

SELECT ROUND(AVG(some_column))
FROM table

Alguém sabe o que estou fazendo de errado?

user1626730
fonte
3
Sua mensagem de erro não corresponde ao código da sua pergunta.
mu é muito curto
À parte o erro de sintaxe, essa questão intimamente relacionada ao dba.SE lança alguma luz sobre o arredondamento de números de precisão dupla no PostgreSQL.
Erwin Brandstetter
@muistooshort, Obrigado por apontar isso. Ele deve dizer 'round' onde diz 'avg'. Editado.
user1626730
para obter resultados de pesquisa, também recebo essa dica como saída do prompt:HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Vzzarr

Respostas:

264

O PostgreSQL não define round(double precision, integer). Por razões que @Mike Sherrill 'Cat Recall' explica nos comentários, a versão da rodada que exige precisão está disponível apenas para 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)

(No exemplo acima, observe que este float8é apenas um atalho para double precision. Você pode ver que o PostgreSQL está expandindo-o na saída).

Você deve converter o valor a ser arredondado numericpara usar a forma de dois argumentos round. Basta acrescentar ::numerico elenco taquigráfico, como round(val::numeric,2).


Se você estiver formatando para exibição para o usuário, não use round. Use to_char(consulte: funções de formatação de tipo de dados no manual), que permite especificar um formato e fornecer um textresultado que não é afetado por qualquer estranheza que o idioma do seu cliente possa fazer com os numericvalores. Por exemplo:

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

to_chararredondará números para você como parte da formatação. O FMprefixo informa to_charque você não deseja nenhum preenchimento com espaços à esquerda.

Craig Ringer
fonte
Hmm. Quando experimento ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, recebo '0.314E1'. E eu tenho meu código escrito ROUND(AVG(val),2)ainda e recebo o erro que descrevi na minha pergunta.
usuário1626730
Acabei ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);de rodar no PgAdmin e Ruby. Com PgAdmin, recebo 3,14, mas com Ruby (usando a jóia Sequel) recebo '0,314E1'. Eu me pergunto por que isso é ...
28612730
12
"Por alguma estranha razão, a versão da rodada que exige precisão está disponível apenas para números". Os números de ponto flutuante são "aproximações úteis". Se você pedir ao código para arredondar um número de ponto flutuante para duas casas decimais, retornando outro número de ponto flutuante, não há garantia de que a aproximação mais próxima da resposta "correta" terá apenas dois dígitos à direita da casa decimal. Numéricos são efetivamente números inteiros em escala; eles não têm esse problema.
Mike Sherrill 'Cat Recall'
@Catcall Bom ponto - uma doubleversão do roundprecisaria retornar numericou (ugh) text, para que também poderia ter um numericargumento.
Craig Ringer
6
Para aqueles que tentam encontrar o comentário de @Catcall: agora é Mike Sherrill 'Cat Recall'
18446744073709551615 7/16/16
88

Experimente também a sintaxe antiga para transmissão,

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

funciona com qualquer versão do PostgreSQL.

Faltam sobrecargas em algumas funções do PostgreSQL, por que (???): Eu acho que "é uma falta" (!), Mas @CraigRinger, @Catcall e a equipe do PostgreSQL concordam com a "lógica histórica da pg".

PS: outro ponto sobre o arredondamento é a precisão , verifique a resposta de @ IanKenney .


Sobrecarga como estratégia de fundição

Você pode sobrecarregar a função ROUND com,

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

Agora sua instrução funcionará bem, tente (após a criação da função)

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

mas retorna um tipo NUMERIC ... Para preservar a primeira sobrecarga de uso comum, podemos retornar um tipo FLOAT quando um parâmetro TEXT é oferecido,

 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;

Experimentar

 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: verificação \df roundapós sobrecargas, mostrará algo como,

Esquema Nome | Tipo de dados do resultado | Tipos de dados do argumento
------------ + ------- + ------------------ + ---------- ------------------
 myschema rodada | precisão dupla | precisão dupla, texto, int
 myschema rodada | numérico | precisão dupla, int
 pg_catalog | rodada | precisão dupla | dupla precisão            
 pg_catalog | rodada | numérico | numérico   
 pg_catalog | rodada | numérico | numérico, int          

As pg_catalogfunções são as padrão, consulte o manual das funções matemáticas integradas .

Peter Krauss
fonte
38

Tente com isto:

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

Ou simplesmente:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
atiruz
fonte
5
Acho que esse é o passo muito mais conciso e direto para frente com minha resposta diária a essa pergunta. : bow:
craastad 02/0318
2
O mesmo aqui! Solução muito curta e útil.
Alexey Shabramov 03/07/19
7

você pode usar a função abaixo

 SELECT TRUNC(14.568,2);

o resultado mostrará:

14.56

você também pode converter sua variável no tipo de desejo:

 SELECT TRUNC(YOUR_VAR::numeric,2)
AdagioDev
fonte
3

De acordo com a resposta de Bryan, você pode fazer isso para limitar os decimais em uma consulta. Converter de km / h para m / se exibi-lo em dygraphs, mas quando o fiz em dygraphs, parecia estranho. Parece bom ao fazer o cálculo na consulta. Isso está no postgresql 9.5.1.

select date,(wind_speed/3.6)::numeric(7,1) from readings;
kometen
fonte
2

Tente converter sua coluna para um numérico como:

SELECT ROUND(cast(some_column as numeric),2) FROM table
Gabriel Jaime Sierra Rua
fonte
1

Erro: a função round (precisão dupla, número inteiro) não existe

Solução : você precisa adicionar o tipo de conversão para que funcione

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

user5702982
fonte
0

selecione ROUND (SUM (valor) :: numérico, 2) como total_amount FROM transações

dá: 200234.08

vlatko606
fonte