ORACLE 中NUMBER類型默認的精度和Scale問題


ORACLE數據庫中,NUMBER(P,S)是最常見的數字類型,可以存放數據范圍為10^-130~10^126(不包含此值),需要1~22字節(BYTE)不等的存儲空間。P Precison的英文縮寫,即精度縮寫,表示有效數字的位數,最多不能超過38個有效數字。SScale的英文縮寫,表示從小數點到最低有效數字的位數,它為負數時,表示從最大有效數字到小數點的位數。有時候,我們在創建表的時候,NUMBER往往沒有指定PS的值,那么默認情況下,NUMBERPS的值分別是多少呢?相信這個問題能問倒一大片DBA。 在之前,我遇到了一個問題,總結整理在ORACLE NUMBER類型Scale為0引發的問題這篇博客當中,當時武斷的判斷如果不指定psNUMBER類型,它的默認精度值為38, 默認的scale值為0,因為當時參考了官方文檔https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1832

 

clip_image001

 

當然文檔沒有錯誤,文檔應該是指在定義字段數據類型為NUMBER時,指定了NUMBER類型的P值,但是沒有指定S的值,那么Scale默認就是0,如下測試所示,當時應該是我自己沒有完全理解文檔意思,當然文檔也有誤導的嫌疑。

 

 

SQL> drop table test;
 
Table dropped.
 
SQL> create table test(id number(38));
 
Table created.
 
SQL> insert into test
  2  select 123 from dual union all
  3  select 123.123 from dual;
 
2 rows created.
 
SQL> commit;
 
Commit complete.
 
SQL> select * from test;
 
        ID
----------
       123
       123
 
SQL> 

 

 

clip_image002

 

 

當在指定字段類型為NUMBER時,如果PS都不指定,那么PS又是什么值呢?今天特意實驗驗證了一下,具體實驗過程如下:

 

 

SQL> drop table test;
 
Table dropped.
 
SQL> create table test(id  number, id1 number(38,4));
 
Table created.
 
SQL> insert into test                                      
  2  select 12, 12 from dual union all
  3  select 12.123456789, 12.123456789 from dual;
 
2 rows created.
 
SQL> commit;
 
Commit complete.
 
SQL> col id  for 999999999999.999999999999999999999999999999999999;
SQL> col id1 for 99999999999.9999999999999999999999999999999999999;
SQL> select * from test;
 
                                                ID                                                ID1
-------------------------------------------------- --------------------------------------------------
           12.000000000000000000000000000000000000           12.0000000000000000000000000000000000000
           12.123456789000000000000000000000000000           12.1235000000000000000000000000000000000
 
SQL> 

 

 

如上所示,當我插入上面兩條記錄后,發現如果不指定psNUMBER類型,此時的Scale至少是9,我們繼續測試,插入下面數據

 

 

SQL> insert into test
  2  select 12.123456789123456789123456789123456,
  3         12.123456789123456789123456789123456
  4  from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> select * from test;
 
                                                ID                                                ID1
-------------------------------------------------- --------------------------------------------------
           12.000000000000000000000000000000000000           12.0000000000000000000000000000000000000
           12.123456789000000000000000000000000000           12.1235000000000000000000000000000000000
           12.123456789123456789123456789123456000           12.1235000000000000000000000000000000000

 

 

如下所示,此時可以看到Scale的值33了,那么Scale的值是否可以繼續變大呢?

 

clip_image003

 

 

 

SQL> insert into test
  2  select 12.123456789123456789123456789123456789123,
  3         12.123456789123456789123456789123456789123
  4  from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> select * from test;
 
                                                ID                                                ID1
-------------------------------------------------- --------------------------------------------------
           12.000000000000000000000000000000000000           12.0000000000000000000000000000000000000
           12.123456789000000000000000000000000000           12.1235000000000000000000000000000000000
           12.123456789123456789123456789123456000           12.1235000000000000000000000000000000000
           12.123456789123456789123456789123456789           12.1235000000000000000000000000000000000

 

 

如下截圖所示,插入的記錄為12.123456789123456789123456789123456789123,但是顯示的值為12.123456789123456789123456789123456789,總共為38位,由於格式化列的緣故,可能導致部分小數位沒有顯示,

 

 

clip_image004

 

我們繼續測試,調整格式化列,我們發現值變為了12.12345678912345678912345678912345678912,總共40位了,Scale的值為38了。這個是為什么呢?不是數字精度為38,意味着最多是38位嗎?

 

SQL> col id  for 999999999999.99999999999999999999999999999999999999999
SQL> col id1 for 99999999999.999999999999999999999999999999999999999999
SQL> select * from test;
 
                                                     ID                                                     ID1
------------------------------------------------------- -------------------------------------------------------
           12.00000000000000000000000000000000000000000           12.000000000000000000000000000000000000000000
           12.12345678900000000000000000000000000000000           12.123500000000000000000000000000000000000000
           12.12345678912345678912345678912345600000000           12.123500000000000000000000000000000000000000
           12.12345678912345678912345678912345678912000           12.123500000000000000000000000000000000000000

 

clip_image005

 

 

繼續其它測試,我們發現Sacle的值會隨着小數點前面數字的變化而變化,如下所示:

 

SQL> insert into test
  2  select 123456789.123456789123456789123456789123456,
  3         123456789.123456789123456789123456789123456
  4  from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete
 
SQL> insert into test
  2  select 123456789123.123456789123456789123456789123456,
  3         123456789123.123456789123456789123456789123456
  4  from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete.
SQL> select * from test;
 
                                                     ID                                                     ID1
------------------------------------------------------- -------------------------------------------------------
           12.00000000000000000000000000000000000000000           12.000000000000000000000000000000000000000000
           12.12345678900000000000000000000000000000000           12.123500000000000000000000000000000000000000
           12.12345678912345678912345678912345600000000           12.123500000000000000000000000000000000000000
           12.12345678912345678912345678912345678912000           12.123500000000000000000000000000000000000000
    123456789.12345678912345678912345678912300000000000    123456789.123500000000000000000000000000000000000000
 123456789123.12345678912345678912345678910000000000000 #######################################################
 
6 rows selected.

clip_image006

 

 

從上面測試可以看出,Scale的值是變化的,跟數據值有關系,目前看來,小數點前的數字位數和小數點后的數字位數相加為40(有時候又是39),為了測試是否這個規律,我特意用下面案例測試一下

 

 

 

SQL> create table test2(id number);
 
Table created.
 
SQL> insert into test2
  2  select 0.123456789123456789123456789123456789123456789 from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> col id for 9999999999.9999999999999999999999999999999999999999999999;
SQL> select * from test2;
 
                                                        ID
----------------------------------------------------------
           .1234567891234567891234567891234567891235000000
 
SQL> insert into test2
  2  select 123456789.123456789123456789123456789123456789 from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> select * from test2;
 
                                                        ID
----------------------------------------------------------
           .1234567891234567891234567891234567891235000000
  123456789.1234567891234567891234567891230000000000000000
 
SQL> insert into test2
  2  select 123456789123.123456789123456789123456789123456789 from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> select * from test2;
 
                                                        ID
----------------------------------------------------------
           .1234567891234567891234567891234567891235000000
  123456789.1234567891234567891234567891230000000000000000
##########################################################
 
SQL>  col id for 9999999999999.9999999999999999999999999999999999999999999999;
SQL> select * from test2;
 
                                                           ID
-------------------------------------------------------------
              .1234567891234567891234567891234567891235000000
     123456789.1234567891234567891234567891230000000000000000
  123456789123.1234567891234567891234567891000000000000000000
 
SQL> insert into test2
  2  select 12345678912345.12345678912345678912345678912345 from dual;
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> select * from test2;
 
                                                           ID
-------------------------------------------------------------
              .1234567891234567891234567891234567891235000000
     123456789.1234567891234567891234567891230000000000000000
  123456789123.1234567891234567891234567891000000000000000000
#############################################################
 
SQL> col id for 9999999999999999999.99999999999999999999999999999999999999999999;
SP2-0246: Illegal FORMAT string "9999999999999999999.99999999999999999999999999999999999999999999"
SQL> col id for 9999999999999999999.9999999999999999999999999999999999999999
SQL> select * from test2;
 
                                                           ID
-------------------------------------------------------------
                    .1234567891234567891234567891234567891235
           123456789.1234567891234567891234567891230000000000
        123456789123.1234567891234567891234567891000000000000
      12345678912345.1234567891234567891234567900000000000000
 
SQL> 

 

clip_image007

 

 

這個問題糾結了很久,不明白為什么是39或40,后面在Oracle Database SQL Reference 10g Release 2終於找到解釋了,如下所示:

 

p is the precision, or the total number of significant decimal digits, where the most

significant digit is the left-most nonzero digit, and the least significant digit is the

right-most known digit. Oracle guarantees the portability of numbers with

precision of up to 20 base-100 digits, which is equivalent to 39 or 40 decimal digits

depending on the position of the decimal point.

 

p是精度,或是有效十進制數的總位數。最大的有效數字是最左邊的非零數字,而最小有效位是最右邊的數字。 Oracle保證數字的可移植性

精度高達20 base-100 digits,相當於39位或40位十進制數字,取決於小數點的位置。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM