將SQL嵌入到高級語言中混合編程,程序中會含有兩種不同計算模型的語句:
1、SQL語句:描述性的面向集合的語句;負責操縱數據庫。
2、高級語言語句:過程性的面向記錄的語句;負責控制程序流程。
工作單元之間的通信方式:
1、 SQL通信區:向主語言傳遞SQL語句的執行狀態信息;主語言能夠據此控制程序流程。
2、主變量:
(1) 主語言向SQL語句提供參數。
(2) 將SQL語句查詢數據庫的結果交主語言進一步處理。
3、游標:解決集合性操作語言與過程性操作語言的不匹配。
一、SQL通信區
SQLCA:SQL Communication Area。SQLCA是一個數據結構。
SQLCA的用途:
SQL語句執行後,DBMS反饋給應用程序信息:
(1)描述系統當前工作狀態。
(2)描述運行環境。
這些信息將送到SQL通信區SQLCA中,應用程序從SQLCA中取出這些狀態信息,據此決定接下來執行的語句。
SQLCA的使用方法:
用EXEC SQL INCLUDE SQLCA加以定義。SQLCA中有一個存放每次執行SQL語句後返回代碼的變量SQLCODE。如果SQLCODE等於預定義的量SUCCESS,則表示SQL語句成功,否則表示出錯;應用程序每執行完一條SQL 語句之後都應該測試一下SQLCODE的值,以了解該SQL語句執行情況並做相應處理。
例:在執行刪除語句DELETE後,不同的執行情況,SQLCA中有不同的信息:
· 違反數據保護規則,操作拒絕。
· 沒有滿足條件的行,一行也沒有刪除。
· 成功刪除,並有刪除的行數。
· 無條件刪除警告信息。
· 由於各種原因,執行出錯。
二、主變量
嵌入式SQL語句中可以使用主語言的程序變量來輸入或輸出數據。在SQL語句中使用的主語言程序變量簡稱為主變量(Host Variable)。
主變量的類型:
1、 輸入主變量:由應用程序對其賦值,SQL語句引用。
2、 輸出主變量:由SQL語句賦值或設置狀態信息,返回給應用程序。
3、 一個主變量有可能既是輸入主變量又是輸出主變量。
4、 一個主變量可以附帶一個指示變量(Indicator Variable)。
5、 指示變量一個整型變量,用來“指示”所指主變量的值或條件。
指示變量的用途:輸入主變量可以利用指示變量賦空值;輸出主變量可以利用指示變量檢測出是否空值,值是否被截斷。
在SQL語句中使用主變量和指示變量的方法:
1、 說明主變量和指示變量
BEGIN DECLARE SECTION
.........
......... (說明主變量和指示變量)
.........
END DECLARE SECTION
2、 使用主變量
說明之後的主變量可以在SQL語句中任何一個能夠使用表達式的地方出現,為了與數據庫對象名(表名、視圖名、列名等)區別,SQL語句中的主變量名前要加冒號(:)作為標志。
3、 使用指示變量
· 指示變量前也必須加冒號標志。
· 必須緊跟在所指主變量之後。
· 在SQL語句之外(主語言語句中)使用主變量和指示變量的方法。
· 可以直接引用,不必加冒號。
三、游標(cursor)
游標是系統為用戶開設的一個數據緩沖區,存放SQL語句的執行結果。每個游標區都有一個名字,用戶可以用游標逐一獲取記錄,並賦給主變量,交由主語言進一步處理。
為什麼要使用游標?
1、 SQL語言與主語言具有不同數據處理方式。
2、 SQL語言是面向集合的,一條SQL語句原則上可以產生或處理多條記錄。
3、 主語言是面向記錄的,一組主變量一次只能存放一條記錄,僅使用主變量並不能完全。
4、 滿足SQL語句向應用程序輸出數據的要求。
5、 嵌入式SQL引入了游標的概念,用來協調這兩種不同的處理方式。
下面用個程序詳解:
#include
#include
EXEC SQL BEGIN DECLARE SECTION; /*主變量說明開始*/ char deptname[64];
char HSno[64];
char HSname[64];
char HSsex[64];
int HSage;
int NEWAGE;
long SQLCODE;
EXEC SQL END DECLARE SECTION; /*主變量說明結束*/ EXEC SQL INCLUDE sqlca; /*定義SQL通信區*/ /*************************************************************************/ int main(void) /*C語言主程序開始*/ {
int count = 0;
char yn; /*變量yn代表yes或no*/ printf("Please choose the department name(CS/MA/IS): ");
scanf("%s", deptname); /*為主變量deptname賦值*/ EXEC SQL CONNECT TO HP-08D6CXF128B\SQL2000 USER sa; /*連接數據庫TEST*/ EXEC SQL DECLARE SX CURSOR FOR /*定義游標*/ SELECT Sno, Sname, Ssex, Sage /*SX對應語句的執行結果*/ FROM Student
WHERE SDept = :deptname;
EXEC SQL OPEN SX; /*打開游標SX便指向查詢結果的第一行*/ for ( ; ; ) /*用循環結構逐條處理結果集中的記錄*/ {
EXEC SQL FETCH SX INTO :HSno, :HSname, :HSsex,:HSage;
/*推進游標,將當前數據放入主變量*/ if (sqlca->sqlcode != 0) /* sqlcode != 0,表示操作不成功*/ break; /*利用SQLCA中的狀態信息決定何時退出循環*/ if(count++ == 0) /*如果是第一行的話,先打出行頭*/ printf("\n%-10s %-20s %-10s %-10s\n", "Sno", "Sname", "Ssex", "Sage");
printf("%-10s %-20s %-10s %-10d\n", HSno, HSname, HSsex, HSage);
/*打印查詢結果*/ printf("UPDATE AGE(y/n)?"); /*詢問用戶是否要更新該學生的年齡*/ do{
scanf("%c",&yn);
}
while(yn != 'N' && yn != 'n' && yn != 'Y' && yn != 'y');
if (yn == 'y' || yn == 'Y') /*如果選擇更新操作*/ {
printf("INPUT NEW AGE:");
scanf("%d",&NEWAGE); /*用戶輸入新年齡到主變量中*/ EXEC SQL UPDATE Student /*嵌入式SQL*/ SET Sage = :NEWAGE
WHERE CURRENT OF SX ;
} /*對當前游標指向的學生年齡進行更新*/ }
EXEC SQL CLOSE SX; /*關閉游標SX不再和查詢結果對應*/ EXEC SQL COMMIT WORK; /*提交更新*/ EXEC SQL DISCONNECT TEST; /*斷開數據庫連接*/ }