將 float->numeric 強制轉換從賦值更改為隱式,危險嗎?
在將應用程序移植到 PostgreSQL (9.1) 時,我發現的一個奇怪的 SQL 不兼容與
round()
函式有關,特別是採用第二個參數指示舍入精度的版本。在 MySQL 中,
round(some_float_column, 2)
按預期工作,返回some_float_column
四捨五入到小數點後兩位的值。在 Postgres 中,它會出現錯誤ERROR: function round(double precision, integer) does not exist
並建議HINT: No function matches the given name and argument types. You might need to add explicit type casts.
.如文件所示… http://www.postgresql.org/docs/9.1/static/functions-math.html …Postgres 有兩個圓形函式,
round(value)
它採用雙精度或數字,round(value, precision)
它採用僅數字和整數。所以,我不明白為什麼 round 的兩個參數形式不以 double 開頭,但無論如何。在搜尋中,我發現了解決此問題的兩種方法。一種是簡單地創建我自己的版本
round(value, precision)
,需要 (double, int) 並使用顯式轉換包裝現有的 (numeric, int) 版本。這當然可行,但我不喜歡它(我的背景是 Oracle,它甚至沒有真正的浮點類型)。在我看來,float/double 應該可以隱式轉換為數字。事實證明,這些類型的 ASSIGNMENT 強制轉換是預定義的。但是 ASSIGNMENT 不適用於函式呼叫,正如我們在這裡看到的,它需要是隱式的。麻煩的是是每對類型只能定義一個轉換,並且系統需要 float4->numeric 和 float8->numeric 賦值轉換,不能丟棄。因此,使這些強制轉換為隱式的唯一方法是update pg_cast set castcontext = 'i' where castsource in (700,701) and casttarget = 1700
.現在我們正在破解目錄,這表明這可能是一個壞主意。但我沒有任何確鑿的證據表明它是壞的。浮點/雙精度值是不精確的,而數值是精確的,所以在我看來,從前者轉換為後者將完全保留數據,因此在邏輯上是安全的。我知道的唯一潛在問題是將歧義引入其他函式的參數模式,但提出這個問題的目的主要是為了找出我不知道的潛在問題。
那麼,將 float->numeric 轉換行為從 ASSIGNMENT 更改為 IMPLICIT 是否危險?
是的,侵入目錄是不好的。原因 #1 是,如果您升級到新版本並忘記移動 hack,事情就會開始崩潰。只是執行 pg_dump 並在另一個實例上傳入到相同的版本也將失去黑客攻擊。新版本的 Postgres 也總是有可能發生如此大的變化,以至於您現在無法破解並迫使您返回並重新設計。
用你自己的函式覆蓋是正確的方法。
請注意,不同的捨入算法用於不同的數據類型。
https://www.postgresql.org/docs/current/static/datatype-numeric.html#DATATYPE-NUMERIC-TABLE
在舍入值時,數字類型從零開始舍入關係,而(在大多數機器上)實數和雙精度類型將關係舍入到最接近的偶數。例如:
SELECT x, round(x::numeric) AS num_round, round(x::double precision) AS dbl_round FROM generate_series(-3.5, 3.5, 1) as x; x | num_round | dbl_round ------+-----------+----------- -3.5 | -4 | -4 -2.5 | -3 | -2 -1.5 | -2 | -2 -0.5 | -1 | -0 0.5 | 1 | 0 1.5 | 2 | 2 2.5 | 3 | 2 3.5 | 4 | 4