SQL 技巧
1. UPDATE 搭配 SEQUENCE 批次編號
-- 為現有資料補上連續流水號
UPDATE sample SET id = seq_id.NEXTVAL;
-- 條件式更新
UPDATE sample
SET seq_no = seq_id.NEXTVAL
WHERE status = 'PENDING'
AND seq_no IS NULL;
優點:單一 SQL 完成,無需游標迴圈,效能極佳。
2. SELECT 中使用 CASE 運算式
-- 簡單 CASE
SELECT col1,
CASE col1 WHEN 1 THEN 'One' WHEN 2 THEN 'Two' ELSE 'Other' END AS col2
FROM tab;
-- 搜尋 CASE (支援複雜條件)
SELECT col1,
CASE
WHEN col1 > 100 THEN 'High'
WHEN col1 > 50 THEN 'Medium'
ELSE 'Low'
END AS level
FROM tab;
-- 聚合中使用
SELECT deptno,
SUM(CASE WHEN sal > 3000 THEN 1 ELSE 0 END) AS high_sal_cnt,
SUM(CASE WHEN sal <= 3000 THEN 1 ELSE 0 END) AS low_sal_cnt
FROM emp
GROUP BY deptno;
Pro*C/C++ 預編譯與建置
預編譯指令
# 基本編譯
proc iname=file.pc oname=file.c
# 多執行緒支援
proc iname=file.pc oname=file.c threads=yes
# 指定字元集
proc iname=file.pc oname=file.c charset=utf8
# 包含路徑
proc iname=file.pc oname=file.c include=$ORACLE_HOME/precomp/public
編譯鏈結 (Linux/GCC)
# 1. Pro*C 預編譯
proc iname=myapp.pc oname=myapp.c threads=yes
# 2. 編譯 C 產生目標檔
gcc -c -I$ORACLE_HOME/precomp/public -I$ORACLE_HOME/rdbms/public myapp.c -o myapp.o
# 3. 鏈結建立執行檔
gcc myapp.o -o myapp -L$ORACLE_HOME/lib -lclntsh
# 執行前設定 core dump
ulimit -c unlimited
# 除錯
gdb myapp core.9959
關鍵庫與路徑
| 項目 | 路徑/名稱 |
| Pro*C 可執行檔 | $ORACLE_HOME/bin/proc |
| 預編譯公共頭檔 | $ORACLE_HOME/precomp/public |
| RDBMS 公共頭檔 | $ORACLE_HOME/rdbms/public |
| 客戶端共享庫 | libclntsh.so (或 .sl/.dll) |
| 庫路徑 | $ORACLE_HOME/lib |
| 執行期庫路徑環境變數 | LD_LIBRARY_PATH (Linux)、PATH (Windows) |
C/C++ 型別轉換與字串處理
std::string 與 C 風格字串互轉
// string -> const char* (唯讀)
const std::string str = "hello";
const char* cstr = str.c_str(); // 指向內部緩衝區,str 銷毀前有效
// string -> char* (可修改,需複製)
std::string str = "hello";
char* mutable_cstr = new char[str.length() + 1];
std::strcpy(mutable_cstr, str.c_str());
// 使用後 delete[] mutable_cstr;
// char* -> string
const char* cstr = "world";
std::string str(cstr); // 或 string str = cstr;
// 格式化字串 (C++11+)
#include
std::ostringstream oss;
oss << "ID: " << id << ", Name: " << name;
std::string formatted = oss.str();
// C++20 std::format
std::string formatted = std::format("ID: {}, Name: {}", id, name);
空值檢查慣用寫法
// std::string
std::string str;
if (str.empty()) { /* 空字串 */ }
if (!str.empty()) { /* 非空 */ }
// 原始指標
char* ptr = nullptr;
if (ptr == nullptr) { /* 空指標 */ }
if (ptr != nullptr) { /* 非空 */ }
// 智慧指標 (C++11+)
std::unique_ptr uptr;
if (uptr) { /* 非空 */ }
std::shared_ptr sptr;
if (sptr) { /* 非空 */ }
Oracle OCI 型別對應
| Oracle 型別 | C/C++ 型別 | OCI 定義 |
| NUMBER | OCINumber / double / long | OCINumberToReal / OCINumberFromInt |
| VARCHAR2 | char* / std::string | SQLT_CHR / SQLT_STR |
| DATE | OCIDate | OCIDateToText / OCIDateFromText |
| TIMESTAMP | OCIDateTime | OCIDateTimeConstruct |
| RAW | unsigned char* / OCIRaw | SQLT_BIN |
| BLOB/CLOB | OCILobLocator* | OCILobRead / OCILobWrite |
| ROWID | OCIRowid* | SQLT_RDD |
常見 Pro*C 錯誤與解決
| 錯誤 | 原因 | 解決 |
| PCC-S-02015: unable to open include file | 頭檔路徑錯誤 | 檢查 include= 參數、環境變數 |
| PCC-F-02102: fatal error | 語法錯誤、EXEC SQL 區塊未閉合 | 檢查 .pc 原始碼、分號、大括號 |
| undefined reference to sqlcxt | 鏈結缺少 libclntsh | -L$ORACLE_HOME/lib -lclntsh |
| ORA-24756: transaction does not exist | COMMIT/ROLLBACK 不配對 | 檢查 EXEC SQL COMMIT/ROLLBACK 邏輯 |
| Segmentation fault | 指標未初始化、緩衝區溢位 | 啟用 core dump、gdb 除錯、valgrind 檢測 |
效能調優提醒
- 使用
ARRAY FETCH (Pro*C EXEC SQL FETCH ... FOR :n ROWS) 減少網路往返
- 批次
INSERT/UPDATE/DELETE 使用 FOR :n ROWS 陣列操作
- 預編譯選項
RELEASE_CURSOR=YES、HOLD_CURSOR=NO 釋放游標資源
- 啟用
THREADS=YES 支援多執行緒連線池