Jak zaokrąglić średnio do 2 miejsc po przecinku w PostgreSQL?

191

Korzystam z PostgreSQL poprzez „kontynuację” klejnotu Ruby.

Próbuję zaokrąglić do dwóch miejsc po przecinku.

Oto mój kod:

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

Otrzymuję następujący błąd:

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

Po uruchomieniu następującego kodu nie pojawia się błąd:

SELECT ROUND(AVG(some_column))
FROM table

Czy ktoś wie, co robię źle?

użytkownik1626730
źródło
3
Twój komunikat o błędzie nie pasuje do kodu w pytaniu.
mu jest za krótki
Pomijając błąd składniowy, to ściśle powiązane pytanie na dba.SE rzuca nieco światła na zaokrąglanie liczb podwójnej precyzji w PostgreSQL.
Erwin Brandstetter
@muistooshort, dzięki za zwrócenie na to uwagi. Powinien mówić „okrągły”, gdy mówi „średni”. Edytowane.
user1626730,
dla dobra wyników wyszukiwania, otrzymuję również tę wskazówkę jako wynik z monitu:HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Vzzarr

Odpowiedzi:

264

PostgreSQL nie definiuje round(double precision, integer). Z powodów @Mike Sherrill „Cat Recall” wyjaśnia w komentarzach, wersja rundy, która wymaga precyzji, jest dostępna tylko dla 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)

(Powyżej zauważ, że float8to tylko skrótowy skrót dla double precision. Widać, że PostgreSQL rozwija go w wyniku).

Musisz numericużyć wartości, którą chcesz zaokrąglić, aby użyć dwuargumentowej postaci round. Po prostu dołącz ::numericdo stenografii, jak round(val::numeric,2).


Jeśli formatujesz do wyświetlania dla użytkownika, nie używaj round. Użyj to_char(patrz: funkcje formatowania typu danych w instrukcji), która pozwala określić format i daje textwynik, na który nie ma wpływu żadna dziwność, jaką Twój klient może zrobić z numericwartościami. Na przykład:

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

to_charbędzie zaokrąglać liczby w ramach formatowania. FMPrefiks mówi to_char, że nie chce żadnych wyściółkę z czołowych miejsc.

Craig Ringer
źródło
Hmm Kiedy próbuję ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, otrzymuję „0.314E1”. I mam już napisany kod, ROUND(AVG(val),2)ale nadal pojawia się błąd opisany w moim pytaniu.
user1626730,
Właśnie uruchomiłem ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);PgAdmin i Ruby. Z PgAdminem dostaję 3.14, ale z Ruby (używając klejnotu Sequel) dostaję „0.314E1”. Zastanawiam się, dlaczego to jest ...
user1626730,
12
„Z jakiegoś dziwnego powodu wersja rundy, która wymaga precyzji, jest dostępna tylko dla liczb.” Liczby zmiennoprzecinkowe są „przydatnymi przybliżeniami”. Jeśli poprosisz kod o zaokrąglenie liczby zmiennoprzecinkowej do dwóch miejsc po przecinku, zwracając inną liczbę zmiennoprzecinkową, nie ma gwarancji, że najbliższe przybliżenie do „właściwej” odpowiedzi będzie mieć tylko dwie cyfry po prawej stronie dziesiętnej. Liczby to skutecznie skalowane liczby całkowite; nie mają tego problemu.
Mike Sherrill „Cat Recall”
@Catcall Dobra uwaga - doublewersja roundmusiałaby wrócić numericlub (ugh) text, więc równie dobrze mogłaby przyjąć numericargument.
Craig Ringer
6
Dla tych, którzy próbują znaleźć komentarz @Catcall: teraz Mike Sherrill „Cat Recall”
18446744073709551615
89

Spróbuj także starej składni przesyłania,

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

współpracuje z dowolną wersją PostgreSQL.

W niektórych funkcjach PostgreSQL brakuje przeciążeń , dlaczego (???): Myślę, że „to brak” (!), Ale @CraigRinger, @Catcall i zespół PostgreSQL zgadzają się co do „historycznego uzasadnienia pg”.

PS: innym punktem zaokrąglania jest dokładność , sprawdź odpowiedź @ IanKenney .


Przeciążenie jako strategia rzutowania

Możesz przeładować funkcję ROUND za pomocą,

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

Teraz twoja instrukcja będzie działać poprawnie, spróbuj (po utworzeniu funkcji)

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

ale zwraca typ NUMERYCZNY ... Aby zachować pierwsze przeciążenie komom, możemy zwrócić typ FLOAT, gdy oferowany jest parametr 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;

Próbować

 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: sprawdzanie \df roundpo przeciążeniu pokaże coś takiego,

Schemat | Imię | Wynikowy typ danych | Typy danych argumentów
------------ + ------- + ------------------ + ---------- ------------------
 myschema | okrągły | podwójna precyzja | podwójna precyzja, tekst, int
 myschema | okrągły | numeryczny | podwójna precyzja, int
 pg_catalog | okrągły | podwójna precyzja | podwójna precyzja            
 pg_catalog | okrągły | numeryczny | numeryczny   
 pg_catalog | okrągły | numeryczny | numeryczny, int          

Te pg_catalogfunkcje są te domyślne, patrz instrukcja z wbudowanym funkcji matematycznych .

Peter Krauss
źródło
38

Spróbuj tego:

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

Lub po prostu:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
atiruz
źródło
5
Uważam, że jest to o wiele bardziej zwięzły i zdecydowany krok naprzód dzięki mojej codziennej odpowiedzi na to pytanie. : bow:
craastad
2
To samo tutaj! Bardzo krótkie i przydatne rozwiązanie.
Aleksiej Szabramow
7

możesz użyć funkcji poniżej

 SELECT TRUNC(14.568,2);

wynik pokaże:

14.56

możesz także rzutować zmienną na pożądany typ:

 SELECT TRUNC(YOUR_VAR::numeric,2)
AdagioDev
źródło
3

Zgodnie z odpowiedzią Bryana możesz to zrobić, aby ograniczyć liczby dziesiętne w zapytaniu. Przeliczam z km / h na m / s i wyświetlam go na dygraphach, ale kiedy zrobiłem to na dygraphach, wyglądało to dziwnie. Wygląda dobrze podczas wykonywania obliczeń w zapytaniu. To jest na postgresql 9.5.1.

select date,(wind_speed/3.6)::numeric(7,1) from readings;
kometen
źródło
2

Spróbuj przerzucić kolumnę na wartość liczbową, taką jak:

SELECT ROUND(cast(some_column as numeric),2) FROM table
Gabriel Jaime Sierra Rua
źródło
1

Błąd: funkcja okrągłe (podwójna precyzja, liczba całkowita) nie istnieje

Rozwiązanie : Musisz dodać rzutowany typ, to zadziała

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

użytkownik5702982
źródło
0

wybierz OKRĄGŁY (SUMA (kwota) :: numeryczny, 2) jako suma_w sumie Z transakcji

daje: 200234.08

vlatko606
źródło