Come arrotondare una media a 2 decimali in PostgreSQL?


192

Sto usando PostgreSQL tramite il 'sequel' della gemma di Ruby.

Sto cercando di arrotondare al secondo decimale.

Ecco il mio codice:

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

Ottengo il seguente errore:

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

Non ottengo alcun errore quando eseguo il seguente codice:

SELECT ROUND(AVG(some_column))
FROM table

Qualcuno sa cosa sto facendo di sbagliato?


3
Il tuo messaggio di errore non corrisponde al codice nella tua domanda.
mu è troppo corto il

A parte l'errore di sintassi, questa domanda strettamente correlata su dba.SE fa luce sull'arrotondamento dei numeri a doppia precisione in PostgreSQL.
Erwin Brandstetter,

@muistooshort, grazie per averlo segnalato. Dovrebbe dire "round" dove dice "avg". Modificato.
user1626730,

per la ricerca dei risultati, ottengo anche questo suggerimento come output dal prompt:HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Vzzarr

Risposte:


266

PostgreSQL non definisce round(double precision, integer). Per ragioni che @Mike Sherrill 'Cat Recall' spiega nei commenti, la versione del round che richiede una precisione è disponibile solo per 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)

(In precedenza, si noti che float8è solo un alias di stenografia per double precision. Potete vedere che PostgreSQL lo sta espandendo nell'output).

È necessario eseguire il cast del valore da arrotondare numericper utilizzare la forma a due argomenti di round. Basta aggiungere ::numericper il cast di stenografia, come round(val::numeric,2).


Se stai formattando per la visualizzazione per l'utente, non utilizzare round. Usa to_char(vedi: funzioni di formattazione del tipo di dati nel manuale), che ti consente di specificare un formato e ti dà un textrisultato che non è influenzato dalla stranezza che la tua lingua client potrebbe fare con i numericvalori. Per esempio:

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

to_chararrotonderà i numeri per te come parte della formattazione. Il FMprefisso indica to_charche non si desidera alcun riempimento con spazi iniziali.


Hmm. Quando provo ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, ottengo "0.314E1". E ho il mio codice scritto ROUND(AVG(val),2)ancora ottenere ancora l'errore che ho descritto nella mia domanda.
user1626730,

Ho appena corso ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);su PgAdmin e Ruby. Con PgAdmin ottengo 3.14, ma con Ruby (usando la gemma Sequel) ottengo '0.314E1'. Mi chiedo perché questo sia ...
user1626730,

12
"Per qualche strana ragione la versione di round che richiede una precisione è disponibile solo per i numeri." I numeri in virgola mobile sono "approssimazioni utili". Se chiedi al codice di arrotondare un numero in virgola mobile a due cifre decimali, restituendo un altro numero in virgola mobile, non c'è garanzia che l'approssimazione più vicina alla risposta "giusta" avrà solo due cifre alla destra del decimale. I numeri sono numeri interi con scalabilità effettiva; non hanno questo problema.
Mike Sherrill "Cat Recall",

@Catcall Un buon punto: una doubleversione di rounddovrebbe tornare numerico (ugh) text, quindi potrebbe anche prendere un numericargomento.
Craig Ringer,

6
Per coloro che cercano di trovare il commento di @Catcall: ora è Mike Sherrill 'Cat Recall'
18446744073709551615

89

Prova anche la vecchia sintassi per il casting,

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

funziona con qualsiasi versione di PostgreSQL.

Vi sono carenze di sovraccarichi in alcune funzioni di PostgreSQL, perché (???): penso che sia "mancanza" (!), Ma @CraigRinger, @Catcall e il team PostgreSQL concordano sulla "logica storica di pg".

PS: un altro punto sull'arrotondamento è l' accuratezza , controlla la risposta di @ IanKenney .


Sovraccarico come strategia di lancio

È possibile sovraccaricare la funzione ROUND con,

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

Ora le tue istruzioni funzioneranno bene, prova (dopo la creazione della funzione)

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

ma restituisce un tipo NUMERICO ... Per preservare il primo sovraccarico di utilizzo comune, possiamo restituire un tipo FLOAT quando viene offerto un parametro 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;

Provare

 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: il controllo \df rounddopo sovraccarichi, mostrerà qualcosa di simile,

Schema | Nome | Tipo di dati risultato | Tipi di dati dell'argomento
------------ + ------- + ------------------ + ---------- ------------------
 myschema | tondo | doppia precisione | doppia precisione, testo, int
 myschema | tondo | numerico | doppia precisione, int
 pg_catalog | tondo | doppia precisione | doppia precisione            
 pg_catalog | tondo | numerico | numerico   
 pg_catalog | tondo | numerico | numerico, int          

Le pg_catalogfunzioni sono quelle predefinite, vedere il manuale delle funzioni matematiche integrate .


38

Prova con questo:

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

O semplicemente:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67

5
Trovo che questo sia il passo molto più conciso e stretto con la mia risposta quotidiana a questa domanda. : arco:
craastad

2
Anch'io! Soluzione molto breve e utile.
Alexey Shabramov,

7

puoi usare la funzione qui sotto

 SELECT TRUNC(14.568,2);

il risultato mostrerà:

14.56

puoi anche trasmettere la tua variabile al tipo di desiderio:

 SELECT TRUNC(YOUR_VAR::numeric,2)

3

Secondo la risposta di Bryan, puoi farlo per limitare i decimali in una query. Converto da km / h a m / s e lo visualizzo nei grafici, ma quando lo facevo nei grafici sembrava strano. Sembra invece corretto quando si esegue il calcolo nella query. Questo è su postgresql 9.5.1.

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


1

Errore: la funzione round (doppia precisione, intero) non esiste

Soluzione : è necessario aggiungere il tipo di cast, quindi funzionerà

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


0

seleziona ROUND (SUM (importo) :: numerico, 2) come transazioni DA totali_importo

dà: 200234.08

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.