關於DB2除法的小數字問題

2021-09-02 09:05:39 字數 2872 閱讀 4537

今天在做db2測試的時候發現乙個問題:

select 1/3 from sysibm.sysdummy1;    

結果得到: 0!!!!鬱悶,怎麼會這樣。

後來仔細查了一下db2的資料,發現db2的算術運算是遵循一下規則:

argument1                argument2               result

decimal(a,b)             decimal(c,d)            decimal(p,s)

p=max( max(b,d) +  max(a-b,c-d)

s=max(b,d)

但除法的小數字計算遵循下面規則: 31-p+s-s'(其中p為被除數的精度,s為被除數的小數字,s'為除數的小數字)

舉例來講:

1/3 由於,由於兩者資料型別皆為int,所以結果也為int 即結果為0

1.0/3,由於1.0為小數,按照小數除法的規則,

describe select 1.0 from sysibm.sysdummy1;  (2,1)

describe select 3 from sysibm.sysdummy1;     (4,0)

31-2+1-0=31-1=3031-2+1=30,故此保留30位小數。

select 1.0/3 from sysibm.sysdummy1;

結果為:--- 0.333333333333333333333333333333

1/3.0,由於1為int,3.0為小數

describe select 1 from sysibm.sysdummy1;  (4)---4個位元組,共佔10位,其中符號位一位,共11位

describe select 3.0 from sysibm.sysdummy1;     (2,1)

31-11+0-1=31-12=19,故此保留19位小數。

select 1/3.0 from sysibm.sysdummy1;

結果為:---0.3333333333333333333

另外,如果你的db2沒有設定過的話,執行一下語句可能會出錯:

select dec(1,31,0)/dec(1,31,5) from sysibm.sysdummy1; 

報錯說除法運算無效。其實原因就是小數字的問題,按照31-p+s-s'的演算法,31-31+0-5=-5,也即小數字數為-5,小數字又怎麼能是負值呢?所以就報錯了。

此時需要設定乙個引數:min_dec_div_3.   執行以下語句即可

db2 update db cfg for db_name using min_dec_div_3 yes

即將min_dec_div_3的值設定為yes,意思是小數字數取3和按照31-p+s-s' 計算出的小數字兩者的較大值。即是說最小也有3位小數,這樣自然就不會再報錯了。

需要注意的是,雖然可以使用db2 update db cfg 命令來設定min_dec_div_3這個引數,但是實際上這個引數在db cfg 中是不可見的。

也就是說不要指望使用db2 get db cfg for db_name 可以找到它,這是乙個隱藏的引數(搞不懂db2是什麼用意。。。。。。)。

從db2v7版本以上又引入了乙個db2_min_dec_div_6這麼乙個引數,可以將小數字至少儲存6位,如果min_dec_div_3和db2_min_dec_div_6同時為yes,則db2_min_dec_div_6覆蓋min_dec_div_3。

db2_min_dec_div_6這個引數可以使用db2set 來設定:語句為

db2set db2_min_dec_div_6=yes   可以使用db2set -all 來檢視

設完需要重啟db2。

(ps:我使用的是db2 v9.5,伺服器為aix,在我自己的平台上測試min_dec_div_3是可以的,但是無論我把db2_min_dec_div_6設定為yes或者no,都沒看出有什麼效果,不知道是我的設定方法不對還是怎麼回事。)

如果想要最初的語句1/3得到非零值。可以使用如下方法:

(1) select 1.0/3 from sysibm.sysdummy1;   ---得到小數值  結果:  --0.333333333333333333333333333333

(2) select 1/3.0 from sysibm.sysdummy1;  ----同樣得到小數值  結果:  --0.3333333333333333333

(3) select cast(1 as float)/3 from sysibm.sysdummy1;    --使用cast將1轉為float型,然後再才除以3.  結果:0.3333333333333333

(4) select dec(1,10,2)/3 from sysibm.sysdummy1;  ---使用dec函式將1轉換為decimal(10,2),然後除以3 結果:0.33333333333333333333333

其實如果想要把2個數的商四捨五入儲存兩位小數,

oracle中可以直接使用round函式即可:

select round(a/b,2) from dual;

而db2中卻要繞幾個彎才行:需要使用

select dec(cast(a as float)/b+0.005,10,2) from sysibm.sysdummy1;   先用cast轉換a為float型,然後運算,再使用+0.005作為四捨五入,然後再使用dec擷取2位小數。或者:

select cast(round(cast(a as float)/b,2) as decimal(10,2)) from sysibm.sysdummy1; 先使用cast轉a為float,然後運算,再使用round四捨五入取2位小數,然後使用cast轉換為decimal(10,2)型。

哎。。。可憐的db2啊。

下邊貼乙個關於db2小數字的英文文獻供參考:

DB2之DECIMAL小數字數導致的乘法溢位

decimal值型別最長為31位,它在做乘法運算的時候,會將小數字數自動加和而擠占整數字,直到擠占完畢導致結果溢位。比如a decimal 24,6 b decimal 24,6 則a b的結果是decimal 31,12 比如a decimal 5,2 b decimal 6,3 則a b的結果是...

關於DB2的使用(DB2資料命令)

公司所用的資料庫有金倉和db2 首先要用命令視窗直接開啟db2需要在cmd中輸入 db2cmd 1 啟動db2資料庫 db2start 2 連線資料庫 db2 connect to 資料庫名稱 3 建立資料庫 db2 create db 資料庫名稱 4 刪除資料庫 db2 drop db 資料庫名稱...

關於DB2的日常學習

場景一 需要插入的資料做了id非重複的控制,但沒有做自增加,提前準備的指令碼的時候,你也不知道生產資料庫裡id到多少了。解決方式 在insert語句中嵌入select語句,實時獲取最新一條資料的id demo insert into esb2 flow ctrl dimension,keyword,...