承接上篇環境配置,本文深入解析 Oracle COM 自動化核心套件 ORDCOM 的函數規格、PL/SQL 與 COM Variant 型別對應表,並以 Excel 物件模型為例,詳細拆解從 Application 到 Range 到 Font 的層層物件導航與屬性/方法呼叫實作細節。
| 函數 | 參數說明 | 回傳/輸出 |
|---|---|---|
| CreateObject(progid, ctx, reserved, handle) | ProgID/CLSID, 執行內容, 保留, 物件控制代碼(OUT) | 狀態碼 |
| DestroyObject(handle) | 物件控制代碼 | 狀態碼 |
| GetLastError | 無 | 錯誤訊息字串 |
| GetProperty(handle, propName, argCount, value) | 物件, 屬性名, 參數數(通常0), 值(OUT) | 狀態碼 |
| SetProperty(handle, propName, argCount, value) | 物件, 屬性名, 參數數, 值 | 狀態碼 |
| InitArg | 初始化參數陣列 | — |
| InitOutArg | 初始化輸出參數 | — |
| GetArg(token, index, value) | Invoke token, 參數索引(1-based), 值(OUT) | 狀態碼 |
| SetArg(token, index, value, type) | Invoke token, 索引, 值, 型別名(BSTR/INT/BOOL...) | 狀態碼 |
| Invoke(handle, methodName, token) | 物件, 方法名, 參數token | 狀態碼 |
| PL/SQL | COM Variant (VT_*) | 說明 |
|---|---|---|
| VARCHAR2 | VT_BSTR | Unicode 字串,SetArg 時指定 'BSTR' |
| BOOLEAN | VT_BOOL | VARIANT_TRUE (-1) / VARIANT_FALSE (0) |
| BINARY_INTEGER | VT_I2, VT_I4, VT_UI1 | BYTE/INT/LONG,SetArg 指定 'I2'/'I4'/'UI1' |
| DOUBLE PRECISION | VT_R8, VT_R4, VT_CY | DOUBLE/FLOAT/CURRENCY |
| DATE | VT_DATE | OLE Automation 日期格式 (Double) |
STARTUP_WAIT_TIME_LISTENER = 0
CONNECT_TIMEOUT_LISTENER = 10
TRACE_LEVEL_LISTENER = OFF
PASSWORDS_LISTENER = (Oracle)
設定後需重啟監聽器生效。
VBA 寫法:Range("A1").Font.Size = 20
ORDCOM 需拆解為:
CreateObject('Excel.Application'))Workbooks.Add 或 Workbooks.Open)ActiveSheet 或 Sheets(1))Range("A1") 或 Cells(1,1))Range.Font)Font.Size = 20)DECLARE
h_app BINARY_INTEGER;
h_wb BINARY_INTEGER;
h_ws BINARY_INTEGER;
h_range BINARY_INTEGER;
h_font BINARY_INTEGER;
h_token BINARY_INTEGER;
v_status BINARY_INTEGER;
BEGIN
-- 1. 建立 Excel
v_status := ORDCOM.CreateObject('Excel.Application', 0, NULL, h_app);
IF v_status != 0 THEN RAISE_APPLICATION_ERROR(-20001, 'Create Excel failed: '||ORDCOM.GetLastError); END IF;
-- 2. 不顯示視窗
v_status := ORDCOM.SetProperty(h_app, 'Visible', 0, FALSE);
-- 3. 新增活頁簿
ORDCOM.InitArg;
v_status := ORDCOM.Invoke(h_app, 'Workbooks.Add', h_token);
v_status := ORDCOM.GetArg(h_token, 1, h_wb);
-- 4. 取得工作表
v_status := ORDCOM.GetProperty(h_wb, 'ActiveSheet', h_ws);
-- 5. 寫入標題 A1:C1
v_status := ORDCOM.GetProperty(h_ws, 'Range("A1:C1")', h_range);
v_status := ORDCOM.SetProperty(h_range, 'Value', 0, '部門,員工數,平均薪資');
-- 6. 設定標題字型
v_status := ORDCOM.GetProperty(h_range, 'Font', h_font);
v_status := ORDCOM.SetProperty(h_font, 'Bold', 0, TRUE);
v_status := ORDCOM.SetProperty(h_font, 'Size', 0, 14);
v_status := ORDCOM.SetProperty(h_font, 'Color', 0, 0xFFFFFF); -- 白字
-- 7. 設定儲存格底色
v_status := ORDCOM.GetProperty(h_range, 'Interior', h_font); -- 復用變數
v_status := ORDCOM.SetProperty(h_font, 'Color', 0, 0x003366); -- 深藍底
-- 8. 自動調整欄寬
v_status := ORDCOM.Invoke(h_range, 'EntireColumn.AutoFit', h_token);
-- 9. 寫入資料列 (示意:第 2 列)
v_status := ORDCOM.GetProperty(h_ws, 'Range("A2:C2")', h_range);
v_status := ORDCOM.SetProperty(h_range, 'Value', 0, 'IT,25,85000');
-- 10. 儲存
ORDCOM.InitArg;
v_status := ORDCOM.SetArg(h_token, 1, 'D:\reports\dept_summary.xls', 'BSTR');
v_status := ORDCOM.Invoke(h_wb, 'SaveAs', h_token);
-- 11. 關閉 Excel
v_status := ORDCOM.Invoke(h_app, 'Quit', h_token);
-- 12. 釋放所有控制代碼
ORDCOM.DestroyObject(h_app);
-- 實務上建議依序釋放 h_range, h_font, h_ws, h_wb, h_app
DBMS_OUTPUT.PUT_LINE('Excel 報表產生完成');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('錯誤: ' || ORDCOM.GetLastError);
-- 確保釋放資源
BEGIN ORDCOM.DestroyObject(h_app); EXCEPTION WHEN OTHERS THEN NULL; END;
RAISE;
END;
Application、Workbook、Worksheet、Range、Font、Interior、Borders| HRESULT | 常見原因 | 對策 |
|---|---|---|
| 0x800401F3 (CO_E_CLASSSTRING) | ProgID 錯誤、Excel 未安裝 | 確認 'Excel.Application' 正確、伺服器安裝 Excel |
| 0x80070005 (E_ACCESSDENIED) | DCOM 權限、服務帳號無桌面互動 | DCOMCNFG 設定啟動權限、或用無介面替代方案 |
| 0x80020006 (DISP_E_UNKNOWNNAME) | 屬性/方法名拼寫錯誤 | 用物件瀏覽器確認正確名稱 |
| 0x8002000E (DISP_E_PARAMNOTOPTIONAL) | Invoke 參數數量/型別不符 | 檢查 InitArg/SetArg 索引與型別 |
Range.Value = VariantArray 比逐儲存格快 100 倍Python + openpyxl 透過外部程序,或 Apache POI Java Stored ProcedureORDCOM 提供了完整的 COM 自動化能力,但每一層物件導航都需顯式呼叫,程式碼冗長且易錯。掌握 CreateObject → GetProperty/Invoke → SetProperty → DestroyObject 的標準模式,善用物件瀏覽器驗證物件模型,並建立可重用的 PL/SQL 封裝套件(如 PKG_EXCEL_REPORT),可將複雜度封裝在資料庫內部。長遠規劃上,建議將格式化報表產出下沉至應用層或微服務,資料庫專注於高效能資料集準備。