嵌入式SQL語(yǔ)言
為什么需要嵌入式SQL語(yǔ)言?
交互式SQL本身不夠靈活, 對(duì)于普通用戶來(lái)說(shuō), 復(fù)雜的查詢掌握起來(lái)太難, 開(kāi)發(fā)應(yīng)用程序很有必要. 而且查詢本身具有復(fù)雜性, 若是能結(jié)合高級(jí)語(yǔ)言的流程控制等特性, 將會(huì)有很大優(yōu)勢(shì).

程序與數(shù)據(jù)庫(kù)連接


SQL語(yǔ)句在執(zhí)行過(guò)程中,必須有提交和撤消語(yǔ)句才能確認(rèn)其操作結(jié)果.
- SQL執(zhí)行的提交:
exec sql commit work; - SQL執(zhí)行的撤消:
exec sql rollback work;
為什么需要提交和撤銷?
先了解一下事務(wù)的概念:
事務(wù)
(從應(yīng)用程序員角度)是一個(gè)存取或改變數(shù)據(jù)庫(kù)內(nèi)容的程序的一次執(zhí)行,或者說(shuō)一條或多條SQL語(yǔ)句的一次執(zhí)行被看作一個(gè)事務(wù).
事務(wù)一般是由應(yīng)用程序員提出,因此有開(kāi)始和結(jié)束, 結(jié)束前需要提交或撤消。
Begin Transaction
exec sql …
…
exec sql …
exec sql commit work | exec sql rollback work
End Transaction
在嵌入式SQL程序中,任何一條數(shù)據(jù)庫(kù)操縱語(yǔ)句(如exec sql select等)都會(huì)引發(fā)一個(gè)新事務(wù)的開(kāi)
始,只要該程序當(dāng)前沒(méi)有正在處理的事務(wù)。而事務(wù)的結(jié)束是需要應(yīng)用程序員通過(guò)commit或
rollback確認(rèn)的。因此Begin Transaction和End Transaction兩行語(yǔ)句是不需要的。
事務(wù), 就是提供一組操作, 要么全部執(zhí)行, 要么全部不執(zhí)行, 保證這個(gè)這組操作過(guò)程的完整性.
事務(wù)的特性:
原子性Atomicity
DBMS能夠保證事務(wù)的一組更新操作是原子不可分的,即對(duì)DB而言,要么全做,要么全不做一致性Consistency
DBMS保證事務(wù)的操作狀態(tài)是正確的,符合一致性的操作規(guī)則,它是進(jìn)一步由隔離性來(lái)保證的隔離性Isolation
DBMS保證并發(fā)執(zhí)行的多個(gè)事務(wù)之間互相不受影響。例如兩個(gè)事務(wù)T1和T2, 即使并發(fā)執(zhí)行,也相當(dāng)于或者先執(zhí)行了T1,再執(zhí)行T2; 或者先執(zhí)行了T2, 再執(zhí)行T1持久性Durability: DBMS保證已提交事務(wù)的影響是持久的,被撤銷事務(wù)的影響是可恢復(fù)的.

嵌入式SQL示例:
#include <stdio.h>
#include “prompt.h”
exec sql include sqlca; // SQLCA: SQL communication, Area SQL通信區(qū)
char cid_prompt[ ] = "Please enter customer id: ";
int main()
{
exec sql begin declare section; // 變量聲明
char cust_id[5], cust_name[14];
float cust_discnt;
char user_name[20],user_pwd[20];
exec sql end declare section;
exec sql whenever sqlerror goto report_error; // SQL錯(cuò)誤捕獲語(yǔ)句
exec sql whenever not found goto notfound; // SQL錯(cuò)誤捕獲語(yǔ)句
strcpy(user_name, "poneilsql"); // 連接數(shù)據(jù)庫(kù)
strcpy(user_pwd, "*****");
exec sql connect :user_name identified by :user_pwd;
while((prompt(cid_prompt, 1, cust_id, 4)) >=0) {
exec sql select cname,discnt
into :cust_name, :cust_discnt
from customers where cid=:cust_id;
exec sql commit work; // SQL Commit Wort
printf("Customer’s name is %s and discount is %5.1f\n", cust_name,cust_discnt);
continue;
notfound: printf("Can’t find customer %s, continuing\n", cust_id);
}
exec sql commit release;
return 0;
report_error:
print_dberror(); // 打印錯(cuò)誤
exec sql rollback release; // 斷開(kāi)連接
return 1;
}
游標(biāo)
游標(biāo)是什么? 我們?yōu)槭裁葱枰?
檢索單行結(jié)果,可將結(jié)果直接傳送到宿主程序的變量中.例如:
exec sql select Sname, Sage into :vSname, :vSage from Student where Sname = :specName ;
檢索多行結(jié)果, 就需要使用游標(biāo)(Cursor)
- 游標(biāo)是指向某檢索記錄集的指針
- 通過(guò)這個(gè)指針的移動(dòng), 每次讀一行處理一行, 再讀一行...., 直到處理完畢
- 讀一行通過(guò)Fetch...into語(yǔ)句實(shí)現(xiàn), 每次Fetch, 都是向下移動(dòng)指針, 然后再讀取
- 記錄集有結(jié)束標(biāo)識(shí)EOF, 用來(lái)標(biāo)記后面已沒(méi)有記錄了

游標(biāo)的使用:
游標(biāo)(Cursor)的使用需要先定義、再打開(kāi)(執(zhí)行)、接著一條接一條處理,最后再關(guān)閉. 可以定義一次, 多次打開(kāi).
exec sql declare cur_student cursor for
select Sno, Sname, Sclass from Student where Sclass='035101' ;
exec sql open cur_student;
exec sql fetch cur_student into :vSno, :vSname, :vSclass;
… …
exec sql close cur_student;
可滾動(dòng)的游標(biāo)
標(biāo)準(zhǔn)的游標(biāo)總是從上往下的讀的. 但是我們想向上向下滾動(dòng)讀取. ODBC(Open DataBase Connectivity)是一種跨DBMS的DB操作平臺(tái), 它在應(yīng)用程序與實(shí)際的DBMS之間提供了一種通用接口, 可以幫助我們實(shí)現(xiàn)滾動(dòng)游標(biāo).
數(shù)據(jù)庫(kù)記錄的刪除與更新
刪除
查找刪除:
exec sql delete from customers c where c.city = 'Harbin' and
not exists ( select * from orders o where o.cid = c.cid);
定位刪除:
exec sql declare delcust cursor for
select cid from customers c where c.city =‘harbin’ and
not exists ( select * from orders o where o.cid = c.cid)
for update of cid;
exec sql open delcust
While (TRUE) {
exec sql fetch delcust into :cust_id;
exec sql delete from customers where current of delcust ;
}
更新
一種是查找更新, 一種是定位更新
查找更新:
exec sql update student s set sclass = "035102"
where s.sclass = "034101"
定位更新:
exec sql declare stud cursor for
select * from student s where s.sclass ="034101"
for update of sclass;
exec sql open stud
While (TRUE) {
exec sql fetch stud into :vSno, :vSname, :vSclass;
exec sql update student set sclass = "035102" where current of stud ;
}
數(shù)據(jù)庫(kù)插入
exec sql insert into student ( sno, sname, sclass)
values ('03510128', '張三', '035101') ;
狀態(tài)捕獲及其處理
狀態(tài), 是嵌入式SQL語(yǔ)句的執(zhí)行狀態(tài), 尤其指一些出錯(cuò)狀態(tài), 有時(shí)程序需要知道這些狀態(tài)并對(duì)這些狀態(tài)進(jìn)行處理.
嵌入式SQL程序中, 狀態(tài)捕獲及處理有三部分構(gòu)成:
- 設(shè)置SQL通信區(qū): 一般在嵌入式SQL程序的開(kāi)始處便設(shè)置
exec sql include sqlca; - 設(shè)置狀態(tài)捕獲語(yǔ)句: 在嵌入式SQL程序的任何位置都可以設(shè)置, 可以多次設(shè)置, 但是有作用域
exec sql whenever sqlerror goto report_error; - 狀態(tài)處理語(yǔ)句: 某一段程序以應(yīng)對(duì)SQL的某種狀態(tài)
report_error: exec sql rollback;
SQL通信區(qū): SQLCA
- SQLCA是一個(gè)已被聲明過(guò)的具C語(yǔ)言的結(jié)構(gòu)形式的內(nèi)存信息區(qū),其中的成員變量用來(lái)記錄SQL語(yǔ)句執(zhí)行的狀態(tài),便于宿主程序讀取與處理
-
SQLCA是DBMS(執(zhí)行SQL語(yǔ)句)與宿主程序之間交流的橋梁之一
狀態(tài)捕獲語(yǔ)句
exec sql whenever condition action;
Whenever語(yǔ)句的作用是設(shè)置一個(gè)"條件陷阱", 當(dāng)滿足條件的時(shí)候, 就會(huì)執(zhí)行相應(yīng)的動(dòng)作.

作用范圍, 兩個(gè)whenever 之間, 否則直到程序結(jié)束.
注意:作用域是語(yǔ)句在程序中的位置,而不是控制流程(因是預(yù)編譯程序處理?xiàng)l件陷阱)


回顧

