Pro*C的常用動態SQL技術一共有3種:
- 用於處理不包含宿主變量的動態SQL, 不能用於SELECT語句.
- 用於處理輸入宿主變量個數和類型已經確定的動態SQL, 不能用於SELECT語句.
- 用於處理選擇列表項和輸入宿主變量個數已經確定的動態SQL, 此種方法可以處理所有前兩種方法能處理的情況, 此外, 還能處理SELECT語句.
由於第3種方法已經包含前兩種方法的處理范圍, 這篇文章我們主要介紹第3種方法.
1 介紹:
1.1 適用語句:
- DML(Data Manipulation Language 數據操縱語言)
- DDL(Data Definition Language 數據定義語言)
- DCL(Data Control Language 數據控制語言)
- 以及事務控制語句
- 而且還可以處理SELECT語句
用SQL語句舉例就是:
- DELETE FROM tbl_name WHERE name=xxx
- CREATE TABLE tbl_name(cola INT)
- GRANT SELECT ON xx TO xxx
- COMMIT
- INSERT INTO tbl_name VALUES(:a)
- DELETE FROM tbl_name WHERE name=:a
- SELECT name FROM tbl_name WHERE no=xxx
1.2 不能處理的語句:
總體來講就是對象名和列名不能使用宿主變量, 例如:
- INSERT INTO :a VALUES(:b)
- SELECT :a, :b FROM tbl_name WHERE name=:c
2 處理步驟:
2.1 PREPARE語句:
PREPARE命令用於明明和解析SQL語句, 語法如下:
EXEC SQL PREPARE statement_name
FROM {:host_string | string_literal};
說明:
- statement_name: 預編譯器標識符.
- host_string: 包含SQL語句的宿主變量.
- string_literal: SQL語句文本字符串.
2.2 DECLARE游標:
使用PREPARE准備了SQL語句之後, 應該執行內嵌DECLARE命令定義游標, 語法如下:
EXEC SQL DECLARE cursor_name CURSOR FOR statement_name;
說明:
- cursor_name: 游標名.
- statement_name: statement標識符, 在PREPARE過程中使用的.
2.3 OPEN打開游標:
當開始游標時, 會執行游標所對應的SQL語句, 語法如下:
EXEC SQL OPEN cursor_name [USING host_variable_list];
說明:
- cursor_name: 游標名, 前面DECLARE的.
- host_variable_list: 輸入的宿主變量列表.
當執行OPEN命令時, 如果SQL語句不是SELECT語句, 會直接執行該語句, 此後可以關閉游標; 如果SQL語句是SELECT語句, 那麼會將查詢結果放到游標結果集中, 還必須使用內嵌的FETCH語句提取並處理游標結果集, 之後再關閉游標.
2.4 FETCH提取游標數據:
當SQL語句是SELECT語句時, OPEN之後會把結果存放到游標結果集中, 為了處理查詢結果, 需要使用FETCH來提取數據, 語法如下:
EXEC SQL FETCH cursor_name INTO host_variable_list;
說明:
cursor_name: 游標名, 前面OPEN的.
host_variable_list: 輸入的宿主變量列表.
2.5 CLOSE關閉游標:
提取並處理完游標數據後, 關閉游標, 語法如下:
EXEC SQL CLOSE cursor_name;
3 代碼舉例:
/* 大組成員表結構 */struct GrpMember
{
char str_bgID[22]; /* 大組ID */ char str_matID[22]; /* 素材ID */ ...
...
};
/**
* 素材檢索
* 填沖好一個輸入結構, 作為函數的參數進行調用.
*
* 這個輸入結構中的各各成員項可以為空,
* 通過判斷來確定數據庫檢索條件, 即: SELECT語句後面的條件.
*
*/void MatSearch(struct GrpMember *in)
{
/* 定義臨時變量 */ char buf[256]; /* buffer */ /* 定義宿主變量 */ EXEC SQL BEGIN DECLARE SECTION;
char sql_buf[1024]; /* 存放SQL語句 */ struct GrpMember ret; /* 查詢結果 */ EXEC SQL END DECLARE SECTION;
/**
* 根據參數, 構造SQL語句
*
* 1 把SQL語句的前半部分拷貝到buffer中.
* 2 判斷輸入參數的結構中各成員項是否為空, 如不為空, 則add到buffer中.
*/ strcpy(sql_buf, "SELECT * FROM TBL_GRPMEMBER WHERE 1=1 ");
if (!isEmpty(str_bgID))
{
sprintf(buf, "AND tbl_str_bgID = %s ", str_bgID);
strcat(sql_buf, buf);
}
...
...
/* 准備動態SQL */ EXEC SQL PREPARE sql_stmt FROM :sql_buf;
/* 定義游標 */ EXEC SQL DECLARE c1 CURSOR FOR sql_stmt;
/* 打開游標: 執行查詢 */ EXEC SQL OPEN c1;
/* 提取查詢結果 */ while(1)
{
EXEC SQL FETCH c1 INTO ret; /* 此處偽代碼, 應該逐項INTO, 逗號分割, 具體見游標的使用 */ }
EXEC SQL CLOSE c1;
}