¿Cómo redondear un promedio a 2 decimales en PostgreSQL?

191

Estoy usando PostgreSQL a través de la 'secuela' de Ruby gem.

Estoy tratando de redondear a dos decimales.

Aquí está mi código:

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

Obtuve el siguiente error:

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

No obtengo ningún error cuando ejecuto el siguiente código:

SELECT ROUND(AVG(some_column))
FROM table

¿Alguien sabe lo que estoy haciendo mal?

usuario1626730
fuente
3
Su mensaje de error no coincide con el código en su pregunta.
mu es demasiado corto el
Dejando a un lado el error de sintaxis, esta pregunta estrechamente relacionada sobre dba.SE arroja algo de luz sobre el redondeo de números de doble precisión en PostgreSQL.
Erwin Brandstetter
@muistooshort, gracias por señalarlo. Debería decir 'redondo' donde dice 'promedio'. Editado
usuario1626730
para buscar resultados, también recibo esta pista como resultado de la solicitud:HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Vzzarr

Respuestas:

264

PostgreSQL no define round(double precision, integer). Por razones que @Mike Sherrill 'Cat Recall' explica en los comentarios, la versión de ronda que requiere precisión solo está disponible 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)

(En lo anterior, tenga en cuenta que float8es solo un alias abreviado para double precision. Puede ver que PostgreSQL lo está expandiendo en la salida).

Debe convertir el valor a redondear numericpara usar la forma de dos argumentos de round. Solo agrega ::numericel elenco de taquigrafía, como round(val::numeric,2).


Si está formateando para mostrar al usuario, no lo use round. Use to_char(vea: funciones de formato de tipo de datos en el manual), que le permite especificar un formato y le da un textresultado que no se ve afectado por cualquier rareza que el idioma de su cliente pueda hacer con los numericvalores. Por ejemplo:

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

to_charredondeará los números para usted como parte del formateo. El FMprefijo dice to_charque no desea ningún relleno con espacios iniciales.

Craig Ringer
fuente
Hmm Cuando pruebo ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, obtengo '0.314E1'. Y todavía tengo mi código escrito, ROUND(AVG(val),2)todavía recibo el error que describí en mi pregunta.
usuario1626730
Acabo de correr ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);en PgAdmin y Ruby. Con PgAdmin, obtengo 3.14, pero con Ruby (usando la gema Sequel) obtengo '0.314E1'. Me pregunto por qué esto es ...
user1626730
12
"Por alguna extraña razón, la versión de ronda que toma una precisión solo está disponible para numéricos". Los números de punto flotante son "aproximaciones útiles". Si le pide al código que redondee un número de coma flotante a dos decimales, devolviendo otro número de coma flotante, no hay garantía de que la aproximación más cercana a la respuesta "correcta" tenga solo dos dígitos a la derecha del decimal. Los números son enteros efectivamente escalados; No tienen ese problema.
Mike Sherrill 'Cat Recall'
@Catcall Buen punto: una doubleversión de roundtendría que regresar numerico (ugh) text, por lo que también podría tomar una numericdiscusión.
Craig Ringer
66
Para aquellos que intentan encontrar el comentario de @Catcall: ahora es Mike Sherrill 'Cat Recall'
18446744073709551615
88

Pruebe también la antigua sintaxis para emitir,

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

funciona con cualquier versión de PostgreSQL.

Hay una falta de sobrecargas en algunas funciones de PostgreSQL, ¿por qué (???): Creo que "es una falta" (!), Pero @CraigRinger, @Catcall y el equipo de PostgreSQL están de acuerdo sobre la "razón histórica de pg".

PD: otro punto sobre el redondeo es la precisión , verifique la respuesta de @ IanKenney .


Sobrecarga como estrategia de lanzamiento

Puede sobrecargar la función REDONDA con,

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

Ahora su instrucción funcionará bien, intente (después de la creación de la función)

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

pero devuelve un tipo NUMÉRICO ... Para preservar la primera sobrecarga de uso común, podemos devolver un tipo FLOAT cuando se ofrece un parámetro 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;

Tratar

 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 

PD: comprobar \df rounddespués de sobrecargas, mostrará algo como,

Esquema | Nombre | Tipo de datos de resultado | Tipos de datos de argumentos
------------ + ------- + ------------------ + ---------- ------------------
 myschema | ronda | doble precisión | doble precisión, texto, int
 myschema | ronda | numérico | doble precisión, int
 pg_catalog | ronda | doble precisión | Precisión doble            
 pg_catalog | ronda | numérico | numérico   
 pg_catalog | ronda | numérico | numérico, int          

Las pg_catalogfunciones son las predeterminadas, consulte el manual de funciones matemáticas integradas .

Peter Krauss
fuente
38

Prueba con esto:

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

O simplemente:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
atiruz
fuente
55
Encuentro que esto es mucho más conciso y más directo con mi respuesta diaria a esta pregunta. : arco:
craastad
2
¡Igual que aquí! Solución muy corta y útil.
Alexey Shabramov
7

puedes usar la siguiente función

 SELECT TRUNC(14.568,2);

el resultado mostrará:

14.56

También puede lanzar su variable al tipo de deseo:

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

Según la respuesta de Bryan, puede hacer esto para limitar los decimales en una consulta. Convierto de km / ha m / s y lo muestro en gráficos, pero cuando lo hice en gráficos me pareció extraño. Se ve bien al hacer el cálculo en la consulta. Esto está en postgresql 9.5.1.

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

Intente convertir su columna a un valor numérico como:

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

Error: la función ronda (precisión doble, entero) no existe

Solución : necesita agregar un tipo de molde, entonces funcionará

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

usuario5702982
fuente
0

seleccione ROUND (SUM (cantidad) :: numérico, 2) como total_amount de las transacciones

da: 200234.08

vlatko606
fuente