前言:打破 PL/SQL 能力邊界
Oracle 8+ 支持外部 C 過程,8i+ 引入 Java,Windows 平台更提供COM 自動化接口,允許 PL/SQL 直接操作 Excel/Word/Outlook 等 Office 組件。本文完整演示:Listener/TNS 配置、COM 包裝器安裝、PL/SQL 調用 Excel 導出實戰。
一、 運行環境與前置條件
- Oracle 9i / Windows 2000
ORACLE_HOME=D:\Oracle\ora92, SID=ORADB, Host=CHANET
- 需監聽器啟用 IPC 協議 以啟動 extproc 進程
二、 核心配置:Listener.ora 與 TNSNames.ora
1. Listener.ora (關鍵:SID_LIST 增加 extproc)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS_LIST = (ADDRESS = (PROTOCOL=TCP)(HOST=CHANET)(PORT=1521)))
(ADDRESS_LIST = (ADDRESS = (PROTOCOL=IPC)(KEY=extproc1))) -- 必須:IPC 啟動 extproc
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC = -- 外部過程專用 SID
(SID_NAME = PLSExtProc)
(ORACLE_HOME = D:\Oracle\ora92)
(PROGRAM = extproc) -- 必須:啟動 extproc 進程
)
(SID_DESC = -- 數據庫實例
(GLOBAL_DBNAME = ORADB)
(ORACLE_HOME = D:\Oracle\ora92)
(SID_NAME = ORADB)
)
)
-- 可選優化參數
STARTUP_WAIT_TIME_LISTENER = 0
CONNECT_TIMEOUT_LISTENER = 10
TRACE_LEVEL_LISTENER = OFF
PASSWORDS_LISTENER = (ORACLE)
2. TNSNames.ora (外部過程連接描述符)
EXTPROC_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST = (ADDRESS = (PROTOCOL=IPC)(KEY=EXTPROC1))) -- 與 Listener KEY 一致
(CONNECT_DATA =
(SID = PLSExtProc) -- 與 Listener SID_NAME 一致
(PRESENTATION = RO) -- 必須:僅遠程操作
)
)
3. 驗證配置
LSNRCTL STOP
LSNRCTL START
TNSPING EXTPROC_CONNECTION_DATA
-- OK (30ms) 表示配置生效
-- 測試 extproc 進程
D:\Oracle\ora92\bin> extproc
-- 顯示版本信息即正常
三、 COM 自動化包裝器安裝 (官方提供)
SQL> CONNECT SYSTEM/chanet@ORADB
SQL> CREATE USER chanet IDENTIFIED BY chanet;
SQL> GRANT CREATE LIBRARY TO chanet;
SQL> CONNECT chanet/chanet@ORADB
SQL> @D:\Oracle\ora92\com\comwrap.sql
-- 此腳本創建 ORDCOM 包,封裝 COM 對象創建/屬性/方法調用
四、 PL/SQL 與 COM 數據類型映射表
| PL/SQL | COM API (Variant) |
| VARCHAR2 | BSTR |
| BOOLEAN | BOOL |
| BINARY_INTEGER | BYTE / INT / LONG |
| DOUBLE PRECISION | DOUBLE / FLOAT / CURRENCY |
| DATE | DATE |
五、 COM 核心 API 函數 (ORDCOM 包)
| 函數 | 功能 |
| CreateObject | 創建 COM 對象 (ProgID/CLSID) |
| DestroyObject | 釋放對象引用 |
| GetProperty | 讀取屬性值 |
| SetProperty | 設置屬性值 |
| InitArg / SetArg | 初始化/設置方法參數 |
| Invoke | 調用方法/過程 |
| InitOutArg / GetArg | 初始化/獲取輸出參數 |
| GetLastError | 獲取最後錯誤信息 |
六、 實戰:PL/SQL 導出數據到 Excel 文件
對象模型鏈路
Application → Workbooks → Worksheet → Range → Font → Size
完整代碼
CREATE OR REPLACE PROCEDURE export_emp_to_excel(p_file VARCHAR2) AS
v_app BINARY_INTEGER; -- COM 對象句柄用整數存儲
v_wb BINARY_INTEGER;
v_ws BINARY_INTEGER;
v_range BINARY_INTEGER;
v_font BINARY_INTEGER;
v_sql VARCHAR2(200);
v_cur INTEGER;
v_col_cnt INTEGER;
v_desc DBMS_SQL.DESC_TAB;
v_val VARCHAR2(4000);
v_row NUMBER := 1;
BEGIN
-- 1. 創建 Excel Application
v_app := ORDCOM.CreateObject('Excel.Application');
ORDCOM.SetProperty(v_app, 'Visible', 0); -- 後台運行
-- 2. 添加 Workbook
v_wb := ORDCOM.GetProperty(v_app, 'Workbooks');
v_wb := ORDCOM.Invoke(v_wb, 'Add');
-- 3. 獲取 ActiveSheet
v_ws := ORDCOM.GetProperty(v_app, 'ActiveSheet');
-- 4. 寫入表頭 (動態獲取列名)
v_sql := 'SELECT * FROM emp';
v_cur := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(v_cur, v_sql, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS(v_cur, v_col_cnt, v_desc);
FOR i IN 1..v_col_cnt LOOP
v_range := ORDCOM.GetProperty(v_ws, 'Cells');
v_range := ORDCOM.Invoke(v_range, 'Item', v_row, i); -- Range(1, i)
ORDCOM.SetProperty(v_range, 'Value', v_desc(i).col_name);
-- 設置表頭加粗
v_font := ORDCOM.GetProperty(v_range, 'Font');
ORDCOM.SetProperty(v_font, 'Bold', 1);
END LOOP;
v_row := 2;
-- 5. 循環寫入數據
WHILE DBMS_SQL.FETCH_ROWS(v_cur) > 0 LOOP
FOR i IN 1..v_col_cnt LOOP
DBMS_SQL.COLUMN_VALUE(v_cur, i, v_val);
v_range := ORDCOM.GetProperty(v_ws, 'Cells');
v_range := ORDCOM.Invoke(v_range, 'Item', v_row, i);
ORDCOM.SetProperty(v_range, 'Value', v_val);
END LOOP;
v_row := v_row + 1;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(v_cur);
-- 6. 保存文件
v_wb := ORDCOM.GetProperty(v_app, 'ActiveWorkbook');
ORDCOM.Invoke(v_wb, 'SaveAs', p_file); -- 完整路徑
-- 7. 關閉 Excel
ORDCOM.Invoke(v_app, 'Quit');
ORDCOM.DestroyObject(v_app);
EXCEPTION
WHEN OTHERS THEN
IF v_app != 0 THEN ORDCOM.DestroyObject(v_app); END IF;
RAISE;
END;
/
七、 關鍵注意事項
| 問題 | 解決方案 |
| Excel 進程殘留 | EXCEPTION 區塊強制 DestroyObject、Quit;監聽器配置 PASSWORDS_LISTENER 防未授權調用 |
| 權限不足 | 運行 Oracle 服務的 OS 用戶需有桌面交互權限、目標目錄寫入權限 |
| 性能 | 單元格級 COM 調用極慢 (萬行級 > 分鐘);大數據量改用 SQL*Loader/外部表/UTL_FILE 生成 CSV |
| 64 位兼容 | 11g+ 64 位 Oracle 需 64 位 Office/COM 組件,否則 extproc 加載失敗 |
八、 總結
外部過程 + COM 自動化實現了「PL/SQL 直接操作 Office」的獨特能力。**配置核心在於 Listener IPC + extproc SID + TNS EXTPROC_CONNECTION_DATA 三位一體**。實戰中,小報表/格式複雜/需公式/圖表 用 COM 導出 Excel;大數據量/高性能/純數據 用 CSV/外部表/ODP.NET。技術選型決定成敗。
- 上一篇文章: Oracle 常見鎖模式速查手冊:7 級模式含義、觸發語句、診斷查殺腳本
- 下一篇文章: Oracle 聯機備份 (Online Backup) 核心原理與實施全流程:ARCHIVELOG 模式下的數據零損失保障
Copyright ©
程式碼之家 All Rights Reserved