數據庫原理與統計筆記-8.1嵌入式SQL

前言

有關數據庫原理與統計的筆記,內容爲書本的原文概括。
你可以根據後面的例題來理解相應的SQL指令。

一、嵌入式SQL的處理過程

嵌入式SQL是將SQL語句嵌入程序設計語言中,被嵌入的程序設計語言,如C、C++、Java等稱爲宿主語言,簡稱主語言。
對嵌入式SQL,數據庫管理系統一般採用預編譯方法處理,即由數據庫管理系統的預處理程序對源程序進行掃描,識別出嵌入式SQL語句,把它們轉換成主語言調用語句,以使主語言編譯程序能識別它們,然後由主語言的編譯程序將純的主語言程序編譯成目標碼。

Created with Raphaël 2.2.0含嵌入式SQL語句的主語言程序關係數據庫管理系統預處理程序轉換嵌入式SQL語句爲函數調用轉換後的主語言程序主語言編譯程序編譯處理目標語言程序

在嵌入式SQL中,爲了能夠快速區分SQL語句與主語言語句,所有SQL語句都必須加前綴。當主語言爲C語言時,語法格式爲:
EXEC SQL <SQL語句>;
如果主語言爲Java,則嵌入式SQL稱爲SQLJ,語法格式爲:
# SQL {<SQL語句>};

二、嵌入式SQL語句與主語言之間的通信

將SQL嵌入到高級語言中混合編程,SQL語句負責操縱數據庫,高級語言語句負責控制邏輯流程,這時程序中會含有兩種不同計算模型的語句。
數據庫工作單元與源程序工作單元之間的通信主要包括:
(1)向主語言傳遞SQL語句的執行狀態信息,使主語言能夠據此信息控制程序流程,主要用SQL通信區實現。
(2)主語言向SQL語句提供參數,主要用主變量實現。
(3)將SQL語句查詢數據庫的結果交主語言處理,主要用主變量和遊標實現。

[1]. SQL通信區

SQL語句執行後,系統要反饋給應用程序若干信息,主要包括描述系統當前工作狀態和運行環境的各種數據。這些信息將送到SQL通信區中,應用程序從SQL通信區中取這些狀態信息,據此決定接下來執行的語句。
SQL通信區在應用程序中用EXEC SQL INCLUDE SQLCA加以定義。SQL通信區中有一個變量SQLCODE,用來存放每次執行SQL語句後返回的代碼。
應用程序每執行完一條SQL語句之後都應該測試一下SQLCODE的值,以瞭解該SQL語句執行情況並做相應處理。如果SQLCODE等於預定義的常量SUCCESS,則表示SQL語句成功,否則在SQLCODE存放錯誤代碼。程序員可以根據錯誤代碼查找問題。

[2]. 主變量

嵌入式SQL語句中可以使用主語言的程序變量來輸入或輸出數據。SQL語句中使用的主語言程序變量簡稱爲主變量。主變量根據其作用的不同分爲輸入主變量和輸出主變量。輸入主變量由應用程序對其賦值,SQL語句引用;輸出主變量由SQL語句對其賦值或設置狀態信息,返回給應用程序。

一個主變量可以附帶一個任選的指示變量,指示變量是一個整型變量,用來指示所指主變量的值或條件。指示變量可以指示輸入主變量是否爲空值,可以檢測輸出主變量是否爲空值,值是否被截斷。
所有主變量和指示變量必須在SQL語句BEGIN DECLARE SECTION 與END DECLARE SECTION之間進行說明。說明之後,主變量可以在SQL語句中任何一個能夠使用表達式的地方出現,爲了與數據庫對象名區別,SQL語句中的主變量名和指示變量前要加冒號作爲標誌。

[3]. 遊標

SQL是面向集合的,一條SQL語句可以產生或處理多條記錄;而主語言是面向記錄的,一組主變量一次只能存放一條記錄。所以僅使用主變量並不能完全滿足SQL語句嚮應用程序輸出數據的要求,爲此嵌入式SQL引入了遊標的概念,用遊標來協調者兩種不同的處理方式。

遊標是系統爲用戶開設的一個數據緩衝區,存放SQL語句的執行結果,每個遊標區都有一個名字。用戶可以通過遊標逐一獲取記錄並賦給主變量,交由主語言進一步處理。

[4]. 建立和關閉數據庫連接

嵌入式SQL程序要訪問數據庫必須先連接數據庫,關係數據庫管理系統根據用戶信息對連接請求進行合法性驗證,只有通過了身份驗證,才能建立一個可用的合法連接。

(1)建立數據庫連接

建立連接的嵌入式SQL語句是:
EXEC SQL CONNECT TO target[AS connection-name][USER user-name];
其中target是要連接的數據庫服務器,是一個常見的服務器標識串,如:<dbname>@<hostname>:<port>,可用是包含服務器標識的SQL串常量,也可以是DEFAULT。
Connection-name是可選的連接名,連接名必須是一個有效的標識符,主要用來識別一個程序內同時建立的多個連接,如果在整個程序內只有一個連接,也可以不指定連接名。

如果程序運行過程中建立了多個連接,執行的所有數據庫單元的工作都在該操作提交時所選擇的當前連接上。程序運行過程中可以修改當前連接,對應的嵌入式SQL語句爲:
EXEC SQL SET CONNECTION connection-name|DEFAULT;

(2)關閉數據庫連接

當某個連接上的所有數據庫操作完成後,應用程序應該主動釋放所佔用的連接資源。關閉數據庫連接的嵌入式SQL語句是:
EXEC SQL DISCONNECTION [connection];
其中connection是EXEC SQL CONNECT所建立的數據庫連接。

[5]. 程序實例

【例】依次檢查某個系的學生記錄,交互式更新某些學生年齡。

EXEC SQL BEGIN DECLARE SECTION;	/*主變量說明開始*/
	char deptname[20];
	char hsno[9];
	char hsname[20];
	char hssex[2];
	int HSage;
	int NEWAGE;
EXEC SQL END DECLARE SECTION; /*主變量說明結束*/
long SQLCODE;
EXEC SQL INCLUDE SQLCODE; /*定義SQL通信區*/
int main(void)
{
	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 TEST@localhost:54321 USER "SYSTEM"/“MANAGER”;	/*連接數據庫TEST*/
	EXEC SQL DECLARE SX CURSOR FOR	/*定義遊標SX*/
		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;
		if(count++==0)	/*如果是第一行時,先打印行頭*/
			printf("\n%-10s %-20s %-10s %-10s\n","Sno","Sname","Ssex","Sage");
		printf("\n%-10s %-20s %-10s %-10s\n",HSno,HSname,HSsex,HSage);	/*打印查詢結果*/
		printf("是否更新該學生年齡(y/n):");
		do{scanf("%c",&yn)}
		while(yn!='N'&&yn!='n'&&yn!='Y'&&yn!='y');
		if(yn=='Y'||yn=='y')	/*選擇更新操作時*/
		{
			printf("年齡:");
			scanf("%d",&NEWAGE);	/*用戶輸入新年齡到主變量中*/
			EXEC SQL UPDATE Student	/*嵌入式SQL更新語句*/
				SET Sage=:NEWAGE
				WHERE CURRENT OF SX;	/*對當前遊標指向的學生年齡進行更新*/
		}
		EXEX SQL CLOSE SX;	/*關閉遊標SX,不在和查詢結果對應*/
		EXEC SQL COMMIT WORK;	/*提交更新*/
		EXEC SQL DISCOUNNECT TEST;	/*斷開數據庫連接*/
	}
}

三、不用遊標的SQL語句

有的嵌入式SQL語句不需要使用遊標,他們是說明性語句、數據定義語句、數據控制語句、查詢結果爲單記錄的SELECT語句、非CURRENT形式的增刪改語句。

[1]. 查詢結果爲但記錄的SELECT語句

這類語句因爲查詢結果只有一個,只需用INTO子句指定存放查詢結果的主變量,不需要使用遊標。

【例】根據學生號碼查詢學生信息。

EXEC SQL SELECT Sno,Sname,Ssex,Sage,Sdept
	INTO :Hsno,:Hsname,:Hsex,:Hage,:Hdept
	FROM Student
	WHERE Sno=:givensno;	/*將要查詢的學生的學號賦給了主變量givensno*/

使用查詢結果爲單記錄的SELECT語句需要注意:
(1)INTO子句、WHERE子句和HAVING短句的條件表示式中均可以使用主變量。
(2)查詢結果爲空值的處理。查詢返回的錄中可能某些列爲空值NULL。爲了表示控制,在INTO子句的主變量後面跟有指示變量,當查詢得出的某個數據項爲空值時,系統會自動將相應主變量後面的指示變量置爲負值,而不再向該主變量賦值。所以當指示變量值爲負值時,不管主變量爲何值,均認爲主變量值爲NULL。
(3)如果查詢結果實際上並不是單條記錄,而是多條記錄,則程序出錯,關係數據庫管理系統會在SQL通信區中返回錯誤信息。

【例】查詢某個學生選修某門課程的成績,假設已經把將要查詢的學生的學號賦給了主變量givensno,將課程號賦給了主變量givencno。

EXEC SQL SELECT Sno,Cno,Grade
	INTO :Hsno,:Hcno,:Hgrade:Gradeid	/*指示變量Gradeid*/
	FROM SC
	WHERE Sno=:givensno AND Cno=:givencno;

如果Gradeid<0,則不論Hgrade爲何值均認爲該學生成績爲空值。

[2]. 非CURRENT形式的增刪改語句

有些非CURRENT形式的增刪改語句不需要使用遊標。在UPDATE的SET子句和WHERE子句中可以使用主變量,SET子句還可以使用指示變量。

【例】修改某個學生選修1號課程的成績。

EXEC SQL UPDATE SC
	SET Grade=:newgrade	/*修改的成績已賦給主變量:newgrade*/
	WHERE Sno=:givensno and Cno=1;	/*學號已賦給主變量:givensno*/

【例】某個學生新選修了某門課程,將有關記錄插入SC表中,假設插入的學號已賦給主變量stdno,課程號已賦給主變量couno,由於該學生剛選修課程,成績應爲空,所以要把只是變量賦爲負值。

gradeid=-1;	/*將指示變量賦爲負值*/
EXEC SQL INSERT
	INTO SC(Sno,Cno,Grade)
	VALUES(:stdno,:couno,:gr:gradeid);	/*:stdno 和 :couno和:gr爲主變量*/

四、使用遊標的SQL語句

必須使用遊標的SQL語句有查詢結果爲多條記錄的SELECT語句、CURRENT形式的UPDATE和DELETE語句。

[1]. 查詢結果爲多條記錄的SELECT語句

一般情況下,SELECT語句查詢結果是多條記錄,因此需要用遊標機制將多條記錄一次一條地送主程序處理,從而把對集合的操作轉換爲對單個記錄的處理。

(1)說明遊標

用DECLARE語句爲一條SELECT語句定義遊標:EXEC SQL DECLARE <遊標名> CURSOR FOR <SELECT語句>;
定義遊標僅僅是一條說明性語句,這時關係數據庫管理系統並不執行SELECT語句。

(2)打開遊標

用OPEN語句將定義的遊標打開。
EXEC SQL OPEN <遊標名>;
打開遊標實際上是執行相應的SELECT語句,把查詢結果取到緩衝區中。這時遊標處於活動狀態,指針指向查詢結果集中的第一條記錄。

(3)推進遊標指針並取當前記錄

EXEC SQL FETCH <遊標名>
INTO <主變量>[<指示變量>][,<主變量>][<指示變量>]...;
其中主變量必須與SELECT語句中的目標列表達式具有一一對應關係,用FETCH語句把遊標指針向前推進一條記錄,同時將緩衝區中的當前記錄取出來送至主變量供主語言進一步處理。通過循環執行FETCH語句逐條取出結果集中的行進行處理。

(4)關閉遊標

用CLOSE語句關閉遊標,釋放結果集佔用的緩衝區及其他資源。
EXEC SQL CLOSE <遊標名>;
遊標被關閉後就不再和原來的查詢結果集相聯繫,但被關閉的遊標可以再次被打開,與新的查詢結果相聯繫。

[2]. CURRENT形式的UPDATE和DELETE語句

UPDATE語句和DELETE語句都是集合操作,如果只想修改或刪除其中某個記錄,則需要用帶遊標的SELECT語句查處所有滿足條件的記錄,從中進一步找出要修改或刪除的記錄,然後用CURRENT形式的UPDATE和DELETE語句修改或刪除之。即UPDATE語句和DELETE語句中要用子句:
WHERE CURRENT OF <遊標名>來表示修改或刪除的是最近一次取出的記錄,即遊標指針指向的記錄。

五、動態SQL

前面所講的嵌入式SQL語句中使用的主變量、查詢目標列、條件都是固定的,屬於靜態SQL語句,靜態嵌入式SQL語句能夠滿足一般要求,但某些應用可能要執行時才能夠確定要提交的SQL語句、查詢的條件,此時就要使用動態SQL語句來解決。
動態SQL方法允許在程序運行過程中臨時組裝SQL語句,動態SQL支持動態組裝SQL語句和動態參數兩種形式,給開發者提供任意SQL語句的能力。

[1].使用SQL語句主變量

程序主變量包含的內容是SQL語句的內容,而不是原來保存數據的輸入或輸出變量,這樣的變量稱爲SQL語句主變量。SQL語句主變量在程序執行期間可以設定不同的SQL語句,然後立即執行。

【例】創建基本表TEST.

EXEC SQL BEGIN DECLARE SECTION;
	const char *stmt="CREATE TABLE test(a int);";	/*SQL語句主變量,內容是創建表的SQL語句*/
EXEC SQL END DECLARE SECTION;
....
EXEC SQL EXECUTE IMMEDIATE :stmt;	/*執行動態SQL語句*/

[2]. 動態參數

動態參數是SQL語句中的可變元素,使用參數符號(?)表示該位置的數據在運行時設定。和前面使用的主變量不同,動態參數的輸入不是編譯時完成綁定,而是通過PREPARE語句準備主變量和執行語句EXECUTE綁定數據或主變量來完成。

(1)聲明SQL語句主變量

SQL語句主變量的值包含動態參數(?)

(2)準備SQL語句(PREPARE)

PREPARE將分析含主變量的SQL語句內容,建立語句中包含的動態參數的內部描述符,並用<語句名>標識它們整體。
EXEC SQL PREPARE <語句名> FROM <SQL語句主變量>

[3]. 執行準備好的語句(EXECUTE)

EXECUTE將SQL語句中分析出的動態參數和主變量或數據常量綁定,作爲語句的輸入或輸出變量
EXEC SQL EXECUTE <語句名> [INTO <主變量表>][USING <主變量或常量>];

【例】向TEST中插入元組

EXEC SQL BEGIN DECLARE SECTION;
	const char *stmt="INSERT INTO TEST VALUES(?);";	/*聲明SQL主變量內容是INSERT語句*/
EXEC SQL END DECLARE SECTION;
...
EXEC SQL PREPARE mystmt FROM :stmt;	/*準備語句*/
...
EXEC SQL EXECUTE mystmt USING 100;	/*執行語句,設定INSERT語句插入值100*/
EXEC SQL EXECUTE mystmt USING 200;	/*執行語句,設定INSERT語句插入值200*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章