((これは Wiki です!編集して強化してください!))
キャストの古い構文も試してください。
SELECT ROUND( AVG(some_column)::numeric, 2 ) FROM table;
PostgreSQL のどのバージョンでも動作します。
...しかし、決定的な解決策として、ROUND 関数をオーバーロードすることができます。
キャスト戦略としてのオーバーロード
CREATE FUNCTION ROUND(float,int) RETURNS NUMERIC AS $f$
SELECT ROUND( CAST($1 AS numeric), $2 )
$f$ language SQL IMMUTABLE;
これで、命令が正常に機能するようになりました。次の完全な比較を試してください。
SELECT trunc(n,3), round(n,3) n_round, round(f,3) f_round,
pg_typeof(n) n_type, pg_typeof(f) f_type, pg_typeof(round(f,3)) f_round_type
FROM (SELECT 2.0/3.0, 2/3::float) t(n,f);
トランク |
n_round |
f_round |
n_type |
f_type |
f_round_type |
0.666 |
0.667 |
0.667 |
数値 |
倍精度 |
数値 |
ROUND(float,int)関数は、(10 進数) NUMERIC データ型を返します。f_round
これは、一部のアプリケーションでは問題ありません: 問題が解決しました!
別のアプリケーションでは、結果としてフロートも必要です。別の方法は、関数を使用round(f,3)::float
または作成するround_tofloat()
ことです。他の代替手段として、ROUND
関数を再度オーバーロードし、浮動小数点数の精度と精度のすべての範囲を使用して、精度が定義されているときに浮動小数点数を返すことです ( IanKenney の回答を参照)。
CREATE FUNCTION ROUND(
input float, -- the input number
accuracy float -- accuracy, the "counting unit"
) RETURNS float AS $f$
SELECT ROUND($1/accuracy)*accuracy
$f$ language SQL IMMUTABLE;
試す
SELECT round(21.04, 0.05); -- 21.05 float!
SELECT round(21.04, 5::float); -- 20
SELECT round(1/3., 0.0001); -- 0.3333
SELECT round(2.8+1/3., 0.5); -- 3.15
SELECT round(pi(), 0.0001); -- 3.1416
PS: オーバーロード後のコマンド\df round
は、psql
次の表のように表示されます
スキーマ | 名前 | 結果 | 口論
------------+---------------------+---------------------+------------------
マイスキーマ | ラウンド | 数値 | フロート、整数
マイスキーマ | ラウンド | フロート | 浮く、浮く
pg_catalog | ラウンド | フロート | 浮く
pg_catalog | ラウンド | 数値 | 数値
pg_catalog | ラウンド | 数値 | 数値、整数
ここで、floatはスキーマを使用しない場合のmyschemadouble precision
と同義です。関数はデフォルトのものです。Guide the build in math functions を参照してください。public
pg_catalog
丸めと整形
この関数はラウンドto_char
プロシージャを内部的に適用するため、端末に最終結果を表示することだけが目的の場合は、修飾子を数値形式パターンのプレフィックスとして使用できます。FM
SELECT round(x::numeric,2), trunc(x::numeric,2), to_char(x, 'FM99.99')
FROM (SELECT 2.0/3) t(x);
円形 |
トランク |
to_char |
0.67 |
0.66 |
.67 |
ノート
問題の原因
一部の PostgreSQL 関数にオーバーロードの欠如があります。なぜ (???): 「それは欠如である」(!) と思いますが、@CraigRinger、@Catcall および PostgreSQL チームは「pg の歴史的根拠」について同意しています。
性能と再利用に関する注意
pg_catalog の ROUND などの組み込み関数は、直接キャスト エンコーディングと比較して、パフォーマンスを損なうことなくオーバーロードできます。高いパフォーマンスを得るためにユーザー定義のキャスト関数を実装する場合は、次の 2 つの予防措置を講じる必要があります。
このIMMUTABLE
節は、このようなコード スニペットにとって非常に重要です。これは、ガイドで述べられているように、「クエリが定数引数で関数を呼び出すときに、オプティマイザが関数を事前評価できるようにする」ためです。
「純粋な SQL」を除いて、PLpgSQL が優先言語です。JIT 最適化(および場合によっては並列処理) ではlanguage SQL
、より適切な最適化が得られます。関数呼び出しを使用する代わりに、小さなコードをコピーして貼り付けるようなものです。
結論:ROUND(float,int)
最適化後の上記の関数は、@CraigRinger の回答よりも高速です。(正確に)同じ内部表現にコンパイルされます。したがって、PostgreSQL の標準ではありませんが、 pg_pubLibのような集中化された再利用可能な「スニペットのライブラリ」によって、プロジェクトの標準にすることができます 。
n 番目のビットまたはその他の数値表現に丸めます
float は 2 進表現であり、ビット数またはその 16 進表現を丸める必要があるため、PostgreSQL が float データ型の数を丸めるのは意味がないと主張する人もいます。
さて、風変わりな提案を追加して、問題を解決しましょう... ここでの目的は、オーバーロードされた別の関数で float 型を返すことです。
ROUND(float, text, int) RETURNS float
text
'dec'
「小数表現」の場合、
'bin'
「バイナリ」表現と
'hex'
16 進表現用。
したがって、異なる表現では、丸められる桁数について異なる解釈があります。dが 10 進数または 16 進数の代わりに 2 進数をカウントしている場合、「小数桁」(元のd桁よりも少ない) を使用して、より短い近似値で数値xを丸めることは短くなります。
C++ なしで「純粋な SQL」を使用するのは簡単ではありませんが、このコード スニペットは説明し、回避策として使用できます。
-- Looking for a round_bin() function! this is only a workaround:
CREATE FUNCTION trunc_bin(x bigint, t int) RETURNS bigint AS $f$
SELECT ((x::bit(64) >> t) << t)::bigint;
$f$ language SQL IMMUTABLE;
CREATE FUNCTION ROUND(
x float,
xtype text, -- 'bin', 'dec' or 'hex'
xdigits int DEFAULT 0
)
RETURNS FLOAT AS $f$
SELECT CASE
WHEN xtype NOT IN ('dec','bin','hex') THEN 'NaN'::float
WHEN xdigits=0 THEN ROUND(x)
WHEN xtype='dec' THEN ROUND(x::numeric,xdigits)
ELSE (s1 ||'.'|| s2)::float
END
FROM (
SELECT s1,
lpad(
trunc_bin( s2::bigint, CASE WHEN xd<bin_bits THEN bin_bits - xd ELSE 0 END )::text,
l2,
'0'
) AS s2
FROM (
SELECT *,
(floor( log(2,s2::numeric) ) +1)::int AS bin_bits, -- most significant bit position
CASE WHEN xtype='hex' THEN xdigits*4 ELSE xdigits END AS xd
FROM (
SELECT s[1] AS s1, s[2] AS s2, length(s[2]) AS l2
FROM (SELECT regexp_split_to_array(x::text,'\.')) t1a(s)
) t1b
) t1c
) t2
$f$ language SQL IMMUTABLE;
試す
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'); -- ERROR, need to cast string
SELECT round(2.8+1/3.,'dec'::text); -- 3 float
SELECT round(2.8+1/3.,'dec',0); -- 3 float
SELECT round(2.8+1/3.,'hex',0); -- 3 float (no change)
SELECT round(2.8+1/3.,'hex',1); -- 3.1266
SELECT round(2.8+1/3.,'hex',3); -- 3.13331578486784
SELECT round(2.8+1/3.,'bin',1); -- 3.1125899906842625
SELECT round(2.8+1/3.,'bin',6); -- 3.1301821767286784
SELECT round(2.8+1/3.,'bin',12); -- 3.13331578486784
また、次の\df round
ものがあります。
Schema | Name | Result | Argument
------------+-------+---------+---------------
myschema | round | float | x float, xtype text, xdigits int DEFAULT 0