Bagaimana cara membulatkan rata-rata ke 2 tempat desimal di PostgreSQL?

192

Saya menggunakan PostgreSQL melalui 'sekuel' Ruby gem.

Saya mencoba membulatkan ke dua tempat desimal.

Ini kode saya:

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

Saya mendapatkan kesalahan berikut:

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

Saya tidak mendapatkan kesalahan ketika saya menjalankan kode berikut:

SELECT ROUND(AVG(some_column))
FROM table

Adakah yang tahu apa yang saya lakukan salah?

pengguna1626730
sumber
3
Pesan kesalahan Anda tidak cocok dengan kode dalam pertanyaan Anda.
mu terlalu pendek
Selain kesalahan sintaks, pertanyaan terkait erat ini pada dba.SE memberi sedikit informasi tentang pembulatan angka presisi ganda dalam PostgreSQL.
Erwin Brandstetter
@muistooshort, Terima kasih sudah menunjukkannya. Itu harus mengatakan 'bulat' di mana dikatakan 'rata'. Diedit.
user1626730
Demi hasil pencarian, saya juga mendapatkan petunjuk ini sebagai output dari prompt:HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Vzzarr

Jawaban:

266

PostgreSQL tidak mendefinisikan round(double precision, integer). Untuk alasan @Mike Sherrill 'Cat Recall' menjelaskan dalam komentar, versi putaran yang membutuhkan ketelitian hanya tersedia untuk 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)

(Pada contoh di atas, perhatikan bahwa float8itu hanya alias singkat untuk double precision. Anda dapat melihat bahwa PostgreSQL mengembangkannya di output).

Anda harus memberikan nilai yang dibulatkan numericke menggunakan bentuk dua argumen round. Cukup tambahkan ::numericuntuk pemain steno, seperti round(val::numeric,2).


Jika Anda memformat untuk tampilan kepada pengguna, jangan gunakan round. Gunakan to_char(lihat: fungsi pemformatan tipe data dalam manual), yang memungkinkan Anda menentukan format dan memberi Anda texthasil yang tidak terpengaruh oleh keanehan apa pun yang mungkin dilakukan oleh bahasa klien Anda dengan numericnilai. Sebagai contoh:

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

to_charakan membulatkan angka untuk Anda sebagai bagian dari pemformatan. The FMawalan memberitahu to_charbahwa Anda tidak ingin padding dengan spasi terkemuka.

Craig Ringer
sumber
Hmm. Ketika saya mencoba ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);, saya mendapatkan '0,314E1'. Dan saya memiliki kode saya yang ditulis ROUND(AVG(val),2)masih mendapatkan kesalahan yang saya jelaskan dalam pertanyaan saya.
user1626730
Saya hanya berlari ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);di PgAdmin dan Ruby. Dengan PgAdmin, saya mendapatkan 3,14, tetapi dengan Ruby (menggunakan he Sequel gem) saya mendapatkan '0,314E1'. Saya ingin tahu mengapa ini ...
user1626730
12
"Untuk beberapa alasan aneh, versi putaran yang membutuhkan ketelitian hanya tersedia untuk numerik." Angka floating-point adalah "perkiraan berguna". Jika Anda meminta kode untuk membulatkan angka titik-mengambang ke dua tempat desimal, mengembalikan angka titik-mengambang lainnya , tidak ada jaminan bahwa perkiraan terdekat dengan jawaban "benar" hanya memiliki dua digit di sebelah kanan desimal. Numerik adalah integer yang diskalakan secara efektif; mereka tidak memiliki masalah itu.
Mike Sherrill 'Cat Recall'
@Catcall Poin bagus - doubleversi roundharus kembali numericatau (ugh) text, jadi mungkin perlu numericargumen.
Craig Ringer
6
Bagi mereka yang mencoba menemukan komentar oleh @Catcall: sekarang adalah Mike Sherrill 'Cat Recall'
18446744073709551615
89

Coba juga sintaks lama untuk casting,

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

berfungsi dengan semua versi PostgreSQL.

Ada kekurangan kelebihan dalam beberapa fungsi PostgreSQL, mengapa (???): Saya pikir "ini kekurangan" (!), Tetapi @CraigRinger, @Catcall dan tim PostgreSQL sepakat tentang "alasan historis pg".

PS: poin lain tentang pembulatan adalah keakuratan , periksa jawaban @ IanKenney .


Overloading sebagai strategi casting

Anda dapat membebani fungsi ROUND dengan,

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

Sekarang instruksi Anda akan berfungsi dengan baik, coba (setelah pembuatan fungsi)

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

tetapi mengembalikan tipe NUMERIC ... Untuk mempertahankan kelebihan penggunaan komom pertama, kita dapat mengembalikan tipe FLOAT ketika parameter TEXT ditawarkan,

 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;

Mencoba

 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: memeriksa \df roundsetelah kelebihan beban, akan menunjukkan sesuatu seperti,

Skema | Nama | Jenis data hasil | Tipe data argumen
------------ + ------- + ------------------ + ---------- ------------------
 myschema | bulat | presisi ganda | presisi ganda, teks, int
 myschema | bulat | numerik | presisi ganda, int
 pg_catalog | bulat | presisi ganda | presisi ganda            
 pg_catalog | bulat | numerik | numerik   
 pg_catalog | bulat | numerik | numerik, int          

The pg_catalogfungsi adalah orang-orang default, lihat manual build-in fungsi matematika .

Peter Krauss
sumber
38

Coba dengan ini:

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

Atau sederhananya:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
atiruz
sumber
5
Saya menemukan ini sebagai langkah yang jauh lebih ringkas dan maju dengan jawaban hari saya untuk pertanyaan ini. : bow:
craastad
2
Sama disini! Solusi yang sangat singkat dan bermanfaat.
Alexey Shabramov
7

Anda dapat menggunakan fungsi di bawah ini

 SELECT TRUNC(14.568,2);

hasilnya akan menunjukkan:

14.56

Anda juga dapat melemparkan variabel Anda ke jenis keinginan:

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

Menurut respons Bryan, Anda dapat melakukan ini untuk membatasi desimal dalam kueri. Saya mengkonversi dari km / jam ke m / s dan menampilkannya dalam dygraphs tetapi ketika saya melakukannya dalam dygraphs itu terlihat aneh. Terlihat baik-baik saja saat melakukan perhitungan dalam kueri. Ini ada di postgresql 9.5.1.

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

Coba casting kolom Anda ke angka seperti:

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

Kesalahan: putaran fungsi (presisi ganda, integer) tidak ada

Solusi : Anda perlu menambahkan jenis cetakan maka itu akan berhasil

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

pengguna5702982
sumber
0

pilih ROUND (SUM (jumlah) :: numerik, 2) sebagai total_amount DARI transaksi

memberi: 200234.08

vlatko606
sumber