Postgresql

將 float->numeric 強制轉換從賦值更改為隱式,危險嗎?

  • September 1, 2018

在將應用程序移植到 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

引用自:https://dba.stackexchange.com/questions/21036