Wie kann man in PostgreSQL einen Durchschnitt auf 2 Dezimalstellen runden?

191

Ich benutze PostgreSQL über das Ruby Gem 'Sequel'.

Ich versuche auf zwei Dezimalstellen zu runden.

Hier ist mein Code:

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

Ich erhalte folgende Fehlermeldung:

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

Ich erhalte keine Fehlermeldung, wenn ich den folgenden Code ausführe:

SELECT ROUND(AVG(some_column))
FROM table

Weiß jemand was ich falsch mache?

user1626730
quelle
3
Ihre Fehlermeldung stimmt nicht mit dem Code in Ihrer Frage überein.
Mu ist zu kurz
Abgesehen vom Syntaxfehler wirft diese eng verwandte Frage zu dba.SE ein wenig Licht auf das Runden von Zahlen mit doppelter Genauigkeit in PostgreSQL.
Erwin Brandstetter
@ Muistooshort, Danke, dass du darauf hingewiesen hast. Es sollte "rund" sagen, wo es "durchschnittlich" sagt. Bearbeitet.
user1626730
Aus Gründen der HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Suchergebnisse erhalte

Antworten:

264

PostgreSQL definiert nicht round(double precision, integer). Aus Gründen, die @Mike Sherrill 'Cat Recall' in den Kommentaren erklärt, ist die Version der Runde, die eine Präzision benötigt, nur für verfügbar 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)

(Beachten Sie oben, dass dies float8nur ein Kurzalias für ist double precision. Sie können sehen, dass PostgreSQL ihn in der Ausgabe erweitert.)

Sie müssen den zu rundenden Wert umwandeln numeric, um die Zwei-Argument-Form von zu verwenden round. Fügen Sie einfach ::numericdie Kurzform hinzu round(val::numeric,2).


Wenn Sie die Anzeige für den Benutzer formatieren, verwenden Sie sie nicht round. Verwenden Sie to_char(siehe: Datentyp-Formatierungsfunktionen im Handbuch), mit dem Sie ein Format angeben und ein textErgebnis erhalten können, das nicht von der Verrücktheit Ihrer Client-Sprache mit numericWerten beeinflusst wird. Beispielsweise:

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

to_charrundet Zahlen für Sie im Rahmen der Formatierung. Das FMPräfix gibt an, to_chardass Sie keine Auffüllung mit führenden Leerzeichen wünschen.

Craig Ringer
quelle
Hmm. Wenn ich es ausprobiere ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, erhalte ich '0.314E1'. Und ich habe meinen Code noch geschrieben, ROUND(AVG(val),2)bekomme aber immer noch den Fehler, den ich in meiner Frage beschrieben habe.
user1626730
Ich bin gerade ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);auf PgAdmin und Ruby gelaufen . Mit PgAdmin bekomme ich 3.14, aber mit Ruby (mit dem Sequel-Juwel) bekomme ich '0.314E1'. Ich frage mich, warum das ist ...
user1626730
12
"Aus irgendeinem Grund ist die Version der Runde, die eine Genauigkeit benötigt, nur für numerische Zwecke verfügbar." Gleitkommazahlen sind "nützliche Näherungen". Wenn Sie den Code auffordern, eine Gleitkommazahl auf zwei Dezimalstellen zu runden und eine andere Gleitkommazahl zurückzugeben, gibt es keine Garantie dafür, dass die nächste Annäherung an die "richtige" Antwort nur zwei Ziffern rechts von der Dezimalstelle hat. Numerische Zahlen sind effektiv skalierte Ganzzahlen. Sie haben dieses Problem nicht.
Mike Sherrill 'Cat Recall'
@Catcall Guter Punkt - eine doubleVersion von roundmüsste zurückgeben numericoder (ugh) text, also könnte es genauso gut ein numericArgument sein.
Craig Ringer
6
Für diejenigen, die versuchen, den Kommentar von @Catcall zu finden: Jetzt ist es Mike Sherrill 'Cat Recall'
18446744073709551615
88

Versuchen Sie auch die alte Syntax für das Casting,

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

funktioniert mit jeder Version von PostgreSQL.

Es gibt einen Mangel an Überladungen in einigen PostgreSQL-Funktionen, warum (???): Ich denke, "es ist ein Mangel" (!), Aber @CraigRinger, @Catcall und das PostgreSQL-Team sind sich über "pgs historische Begründung" einig.

PS: Ein weiterer Punkt beim Runden ist die Genauigkeit . Überprüfen Sie die Antwort von @ IanKenney .


Überladung als Casting-Strategie

Sie können die ROUND-Funktion mit überladen .

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

Jetzt funktioniert Ihre Anweisung einwandfrei. Versuchen Sie es (nach der Funktionserstellung).

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

Es wird jedoch ein NUMERIC-Typ zurückgegeben. Um die erste Überlastung bei der allgemeinen Nutzung zu erhalten, können wir einen FLOAT-Typ zurückgeben, wenn ein TEXT-Parameter angeboten wird.

 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;

Versuchen

 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: Überprüfung \df roundnach Überladungen, zeigt etwas wie,

Schema | Name | Ergebnisdatentyp | Argumentdatentypen
------------ + ------- + ------------------ + ---------- ------------------ ------------------.
 Myschema | rund | doppelte Genauigkeit | doppelte Genauigkeit, Text, Int
 Myschema | rund | numerisch | doppelte Präzision, int
 pg_catalog | rund | doppelte Genauigkeit | Doppelte Genauigkeit            
 pg_catalog | rund | numerisch | numerisch   
 pg_catalog | rund | numerisch | numerisch, int          

Die pg_catalogFunktionen sind die Standardfunktionen, siehe Handbuch der eingebauten mathematischen Funktionen .

Peter Krauss
quelle
38

Versuchen Sie es damit:

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

Oder einfach:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
atiruz
quelle
5
Ich finde, dass dies die viel prägnantere und engere Lösung für meine tägliche Antwort auf diese Frage ist. : Bogen:
Craastad
2
Hier gilt das gleiche! Sehr kurze und nützliche Lösung.
Alexey Shabramov
7

Sie können die folgende Funktion verwenden

 SELECT TRUNC(14.568,2);

Das Ergebnis zeigt:

14.56

Sie können Ihre Variable auch in den gewünschten Typ umwandeln:

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

Laut Bryans Antwort können Sie dies tun, um Dezimalstellen in einer Abfrage zu begrenzen. Ich konvertiere von km / h in m / s und zeige es in Dygraphen an, aber als ich es in Dygraphen gemacht habe, sah es komisch aus. Sieht gut aus, wenn stattdessen die Berechnung in der Abfrage durchgeführt wird. Dies ist auf postgresql 9.5.1.

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

Versuchen Sie, Ihre Spalte in eine Zahl wie folgt umzuwandeln:

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

Fehler: Funktionsrunde (doppelte Genauigkeit, Ganzzahl) existiert nicht

Lösung : Sie müssen einen Typ hinzufügen, damit es funktioniert

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

user5702982
quelle
0

Wählen Sie ROUND (SUM (Betrag) :: numerisch, 2) als total_amount FROM-Transaktionen

gibt: 200234.08

vlatko606
quelle