在 Oracle 資料庫開發中,CHAR 與 VARCHAR2 的儲存行為與比較語義常被誤解。許多開發者直覺認為 VARCHAR2 會自動修剪尾部空白,實際上卻非如此。本文透過實測驗證,釐清這兩種資料型態的真實運作機制,助您避開常見陷阱。
先前普遍認知:CHAR 會以空白補齊至定義長度,VARCHAR2 則按實際長度儲存且不補空白。前兩點確屬實,但第三點「VARCHAR2 儲存時會移除尾部空白」則是錯誤觀念。
實測環境建立測試表:
CREATE TABLE testyyw (col1 CHAR(2), col2 VARCHAR2(2));
INSERT INTO testyyw VALUES ('x', 'x');
INSERT INTO testyyw VALUES ('x ', 'x ');
使用 DUMP 函數檢視實際儲存內容:
SELECT DUMP(col1), DUMP(col2) FROM testyyw;
-- 結果:
-- TYP=96 LEN=2: 120,32 (CHAR: 'x' + 空白)
-- TYP=1 LEN=1: 120 (VARCHAR2: 'x')
-- TYP=96 LEN=2: 120,32 (CHAR: 'x' + 空白)
-- TYP=1 LEN=2: 120,32 (VARCHAR2: 'x' + 空白!)
證據明確:VARCHAR2 確實保留了輸入值的尾部空白,並未自動修剪。
Oracle 採用兩套比較規則:
適用於 CHAR、NCHAR、文字常值、USER 函數回傳值。比較前先以空白補齊較短字串至等長,再逐字元比較。故 'ab' = 'ab ' 為真。
適用於 VARCHAR2、NVARCHAR2。直接按原始長度與內容比較,不補空白。故 'ab' != 'ab '。
實測發現,CHAR 與 VARCHAR2 比較時,Oracle 採用非補齊語義(即按 VARCHAR2 規則),直接比較原始值。這意味著 CHAR(2) 'x ' != VARCHAR2(2) 'x',但 CHAR(2) 'x ' = VARCHAR2(2) 'x '。
TRIM() 或 RTRIM() 統一格式,避免空白導致的邏輯錯誤掌握儲存與比較的細微差異,能有效預防難以追蹤的資料不一致問題,是 Oracle 開發者的必修功課。