NUMBER(p, s) 參數定義
- p (Precision, 精度):有效數字總位數,**1 ~ 38**
- s (Scale, 小數位):小數點右邊位數,**-84 ~ 127**
- 整數位上限 = p - s**
Scale (s) 正負號行為差異
| s 值 | 行為 | 範例 NUMBER(5,2) | 範例 NUMBER(5,-2) |
| s > 0 | 小數點**右邊**保留 s 位,四捨五入 | 123.456 → 123.46 | — |
| s = 0 | 四捨五入至**整數** | 123.456 → 123 | 123.456 → 123 |
| s < 0 | 小數點**左邊**第 |s| 位四捨五入 (十位、百位...) | — | 123.456 → 100 (百位) |
| p < s (s>0) | 純小數,**小數點後前 (s-p) 位必為 0**,保留 s 位小數 | NUMBER(2,5) 存 0.00123 → 0.00123 | — |
實測案例:NUMBER(5,2) vs NUMBER(5,-2) vs NUMBER(2,5)
CREATE TABLE hjm_num_test (
a NUMBER, -- 無限制
b NUMBER(5,2), -- 2 位小數
c NUMBER(5,-2), -- 百位四捨五入
d NUMBER(5,0), -- 整數
e NUMBER(5), -- 等同 NUMBER(5,0)
f NUMBER(2,5) -- 純小數,小數點後前 3 位必為 0
);
INSERT INTO hjm_num_test (a,b,c,d,e,f) VALUES (123.3333, 123.3333, 123.3333, 123.3333, 123.3333, -0.0003);
INSERT INTO hjm_num_test (a,b,c,d,e,f) VALUES (197.9333, 197.9333, 197.9333, 197.9333, 197.9333, 0.00012567);
COMMIT;
SELECT * FROM hjm_num_test;
查詢結果對照
| 欄位 | 定義 | 第 1 列輸入 | 第 1 列儲存 | 第 2 列輸入 | 第 2 列儲存 |
| A | NUMBER | 123.3333 | 123.3333 | 197.9333 | 197.9333 |
| B | NUMBER(5,2) | 123.3333 | 123.33 | 197.9333 | 197.93 |
| C | NUMBER(5,-2) | 123.3333 | 100 | 197.9333 | 200 |
| D | NUMBER(5,0) | 123.3333 | 123 | 197.9333 | 198 |
| E | NUMBER(5) | 123.3333 | 123 | 197.9333 | 198 |
| F | NUMBER(2,5) | -0.0003 | -0.00030 | 0.00012567 | 0.00013 |
工具顯示差異:PL/SQL Developer vs iSQL*Plus / SQL*Plus
| 欄位 | PL/SQL Developer | iSQL*Plus / SQL*Plus | 原因 |
| F (第 1 列) | -0.00030 | -.0003 | SQL*Plus 預設抑制前導/尾隨零 |
| F (第 2 列) | 0.00013 | .00013 | 同上 |
解決顯示差異
-- SQL*Plus / iSQL*Plus 設定
SET NUMFORMAT "0.99999" -- 固定格式
SET NUMWIDTH 20 -- 寬度
COLUMN f FORMAT "0.00000" -- 特定欄位格式
-- 或使用 TO_CHAR 明確格式化
SELECT TO_CHAR(f, 'FM0.00000') FROM hjm_num_test;
NUMBER 子類型對照
| 子類型 | 等價定義 | 用途 |
| INTEGER / INT | NUMBER(38,0) | 整數 |
| SMALLINT | NUMBER(38,0) 但邏輯限制較小 | 相容 ANSI |
| DEC / DECIMAL(p,s) | NUMBER(p,s) | 固定小數位 |
| NUMERIC(p,s) | NUMBER(p,s) | 相容 ANSI |
| FLOAT(p) | 二進制精度 p 位 (1~126) | 近似數值 |
| REAL | FLOAT(63) | 單精度 |
| DOUBLE PRECISION | FLOAT(126) | 雙精度 |
效能與儲存考量
- 儲存大小:可變長度,約 (p/2)+1 bytes,最大 21 bytes
- 運算效能:
PLS_INTEGER / SIMPLE_INTEGER (PL/SQL 區域) 效能遠優於 NUMBER
- 索引大小:NUMBER 索引較 CHAR/VARCHAR2 大
- 避免過度精度:金額用
NUMBER(18,4) 或 NUMBER(15,2) 足矣,勿用 NUMBER(38,*)
最佳實踐建議
- 金額/價格:
NUMBER(18,4) (支援萬億、4 位小數)
- 數量/計數:
NUMBER(10,0) 或 INTEGER
- 比率/百分比:
NUMBER(5,4) (0.0001 ~ 9.9999)
- 科學計算:
BINARY_DOUBLE / BINARY_FLOAT
- PL/SQL 區域變數:迴圈計數器用
PLS_INTEGER、SIMPLE_INTEGER
- 明確指定 p,s:避免隱含
NUMBER(38,*) 浪費空間
常見轉換陷阱
-- 隱含轉換導致精度遺失
INSERT INTO t(num_col) VALUES (1.234567890123456789); -- NUMBER(38,*) 可能截斷
-- 正確:明確精度
INSERT INTO t(num_col) VALUES (1.234567890123456789); -- 目標欄位 NUMBER(20,10) 完整保留
-- 科學記號
INSERT INTO t VALUES (1.23E-5); -- 等同 0.0000123