字符集問題是 Oracle 跨平台遷移、匯入匯出、應用連接最常見的隱形殺手。本文系統梳理:**資料庫字符集 vs 國家字符集**、**常見中文編碼演進**、**字符與編碼轉換實戰**、**NLS_LANG 三層結構對匯入匯出的決定性影響**,助您徹底搞懂字符集機制,避免亂碼災難。
| 屬性 | 資料庫字符集 | 國家字符集 |
|---|---|---|
| 參數名 | NLS_CHARACTERSET | NLS_NCHAR_CHARACTERSET |
| 支援資料型別 | CHAR、VARCHAR2、CLOB、LONG | NCHAR、NVARCHAR2、NCLOB |
| 用途範圍 | 表名、欄位名、PL/SQL 變數、SQL/PLSQL 原始碼儲存 | 多語言 Unicode 資料儲存 |
| 典型值 | ZHS16GBK、AL32UTF8、WE8ISO8859P1 | AL16UTF16(預設)、UTF8 |
| 建立時指定 | CREATE DATABASE ... CHARACTER SET ZHS16GBK | CREATE DATABASE ... NATIONAL CHARACTER SET AL16UTF16 |
鐵律:資料庫建立後**字符集不可變**(除非重建資料庫),國家字符集僅 10g+ 支援 ALTER DATABASE NATIONAL CHARACTER SET(有條件限制)。
AL32UTF8(完整 Unicode 6.0+)、UTF8(舊版 CESU-8,不推薦新建)AL16UTF16(大端序,國家字符集預設)| 標準 | 年份 | 覆蓋範圍 | Oracle 字符集 | 位元組/字 |
|---|---|---|---|---|
| GB2312-80 | 1981 | 6763 漢字 + 682 符號 | ZHS16GBK231280 | 2 |
| GBK | 1995 | 21003 漢字 + 全中日韓統一表意文字 | ZHS16GBK | 2 |
| GB18030 | 2000/2005 | 全 Unicode,含少數民族字 | 無直接對應(建議 AL32UTF8) | 1-4 |
關鍵差異:GBK 為 GB2312 超集,**同一碼位在 GB2312 與 GBK 可能對應不同漢字**(擴充區)。Oracle ZHS16GBK 實為 GBK 編碼,ZHS16GBK231280 嚴格對應 GB2312-80。
-- 查看「蓋」字在資料庫字符集中的內部儲存碼位
SELECT DUMP('蓋') FROM dual;
-- 典型輸出:Typ=96 Len=2: 184,199 (ZHS16GBK 雙位元組)
-- 將十進制碼位轉十六進制
SELECT CONCAT(TO_CHAR(184,'xx'), TO_CHAR(199,'xx')) FROM dual; -- B8 C7
-- 十六進制轉十進制驗證
SELECT TO_NUMBER('B8C7','xxxxxx') FROM dual; -- 47303
-- 十進制碼位轉字符
SELECT CHR(47303) FROM dual; -- 蓋(需 Session 字符集與資料庫一致)
應用場景**:排查亂碼根因、驗證匯入匯出字符集轉換正確性、編寫字符集轉換工具。
NLS_LANG = _.
範例:AMERICAN_AMERICA.ZHS16GBK
SIMPLIFIED CHINESE_CHINA.ZHS16GBK
TRADITIONAL CHINESE_TAIWAN.ZHT16MSWIN950
| 層級 | 參數 | 影響範圍 |
|---|---|---|
| 語言 | NLS_LANGUAGE | Oracle 錯誤訊息語言、月份/星期名稱、日期顯示格式 |
| 地區 | NLS_TERRITORY | 貨幣符號、數字格式(千分位/小數點)、週起始日、ISO 週年 |
| 字符集 | NLS_CHARACTERSET (Client) | 客戶端編碼宣告,決定「應用送出的位元組流」如何被 Oracle 解碼 |
匯出時:
NLS_LANG = 來源資料庫字符集→ 正確讀取來源資料位元組
匯入時:NLS_LANG = 來源資料庫字符集→ Oracle 自動將來源編碼轉換為**目標資料庫字符集**寫入
# 來源 DB: ZHS16GBK,目標 DB: AL32UTF8
# 匯出
export NLS_LANG=SIMPLIFIED_CHINESE_CHINA.ZHS16GBK
exp userid=... file=dump.dmp
# 匯入(關鍵:NLS_LANG 必須設為來源字符集,而非目標!)
export NLS_LANG=SIMPLIFIED_CHINESE_CHINA.ZHS16GBK
imp userid=... file=dump.dmp full=y
原理:匯入時 Oracle 讀取 DMP 檔案標記的來源字符集,對比 Client NLS_LANG 宣告的字符集,若一致則進行 **Server-side Conversion** 轉換為目標資料庫字符集。若 Client NLS_LANG 設為目標字符集(AL32UTF8),Oracle 認為無需轉換,直接寫入 UTF-8 位元組 → **亂碼入庫**。
$ORACLE_HOME/nls/data/lx00023.nlb(簡體)、lx00024.nlb(繁體)$ORACLE_HOME/bin/lbuilder)可視化編輯/建立自訂 Locale 定義AL32UTF8(資料庫字符集)+ AL16UTF16(國家字符集),全 Unicode 支援,零轉換損耗