文章目錄
- 基本概述
- 嵌入式 SQL
- 動態 SQL
- 總結
基本概述
嵌入式SQL和動態SQL是兩種在應用程序中嵌入和使用SQL語句的方法。它們都允許開發人員在編程語言中編寫SQL語句,以便在應用程序中執行數據庫操作。然而,這兩種方法在實現方式、性能和靈活性方面存在一些差異。
嵌入式SQL是一種將SQL語句直接嵌入到宿主語言(如C、C++、Java等)代碼中的方法。在這種情況下,開發人員需要使用特定的語法和預處理器來將SQL語句與宿主語言代碼集成在一起。嵌入式SQL的主要優點是它允許開發人員在編寫應用程序時使用熟悉的宿主語言語法,同時仍然能夠利用SQL的強大功能。此外,嵌入式SQL通常具有較好的性能,因為它允許編譯器在編譯時檢查SQL語句的有效性,并生成優化的代碼。
動態SQL是一種在運行時構建和執行SQL語句的方法。在這種情況下,開發人員需要使用字符串拼接或模板引擎等技術來動態生成SQL語句。然后,這些語句可以在應用程序運行時傳遞給數據庫服務器進行執行。動態SQL的主要優點是它具有很高的靈活性,因為它允許開發人員根據運行時條件構建和修改SQL語句。這使得動態SQL非常適合處理復雜的查詢和更新操作,以及支持用戶自定義的查詢和報告功能。然而,動態SQL的性能可能較差,因為它需要在運行時解析和優化SQL語句,這可能導致額外的開銷。
總的來說,嵌入式SQL和動態SQL各有優缺點。嵌入式SQL適用于那些需要高性能和編譯時錯誤檢查的場景,而動態SQL適用于那些需要高度靈活性和運行時動態生成SQL語句的場景。在選擇使用哪種方法時,開發人員應權衡這些因素,并根據應用程序的具體需求做出決策。
在實際開發過程中,開發人員可能需要結合使用嵌入式SQL和動態SQL。例如,他們可以使用嵌入式SQL編寫大部分數據庫操作,以確保高性能和編譯時錯誤檢查;同時,對于需要高度靈活性的部分,可以使用動態SQL來實現。這種混合方法可以充分利用兩種方法的優點,同時避免它們的局限性。
嵌入式 SQL
SQL 提供了將 SQL 語句嵌入某種高級語言中的使用方式,但是如何識別嵌入在高級語言中的 SQL 語句,通常采用預編譯的方法。該方法的關鍵問題是必須區分主語言中嵌入的 SQL語句,以及主語言和 SQL 間的通信問題。采用的方法由 DBMS 的預處理程序對源程序進行掃描,識別出 SQL 語句,把它們轉換為主語言調用語句,以使主語言編譯程序能識別它,最后由主語言的編譯程序將整個源程序編譯成目標碼。
如何區分主語言語句與 SQL 語句?
需要在所有的 SQL 語句前加前綴 EXEC SQL
,而 SQL 的結束標志隨主語言的不同而不同。
- PL/1 和 C 語言的引用格式為:
EXEC SQL <SQL語句>
; - COBOL 語言的引用格式為:
EXEC SQL <SQL 語句> END-EXEC
;
主語言與數據庫如何通信?
(1)SQL 通信區 (SQL Communication Area,SQLCA) 向主語言傳遞 SQL 語句執行的狀態信息,使主語言能夠根據此信息控制程序流程。
(2)主變量也稱共享變量。主語言向 SQL 語句提供參數主要通過主變量,主變量由主語言的程序定義,并用 SQL 的 DECLARE 語句說明,引用變量一定要加上:
。
EXEC SQL BEGIN DECLARE SECTION; /*說明主變量*/char Msno[4],Mcno[3],Givensno[5];int Mgrade;char SQLSTATE[6];
EXEC SQL END DECLARE SECTION;
分析:以上說明了五個共享變量,其中,SQLSTATE 是一個特殊的共享變量,解釋 SQL 語句執行狀況的作用。當 SQL 語句執行成功時,系統自動給 SQLSTATE 賦值上全零值,否則為非全零(”02000”)。因此,當執行一條SQL語句后,可以根據 SQLSTATE 的值轉向不同的分支,以控制程序的流向。引用時,為了與 SQL 屬性名相區別,需在主變量前加:
。
示例1. 根據共享變量 givensno 值查詢學生關系students 中學生的姓名、年齡和性別。
EXEC SQL SELECT sname,age,sexINTO :Msno,Mcno,:givensnoFROM studentsWHERE sno=:Msno;
示例2. 某學生選修了一門課程信息,將其插入學生選課表SC中,假設學號、課程號、成績已分別賦給主變量HSno、Hcno和Hgrade。
EXEC SQL INSERT INTO SC(Sno,Cno,Grade)VALUES(:Hsno,:Hcno,:Hgrade);
(3)游標。SQL 語言是面向集合的,一條 SQL 語句可產生或處理多條記錄。而主語言是面向記錄的,一組主變量一次只能放一條記錄,所以,引入游標,通過移動游標指針來決定獲取哪一條記錄。
- 定義游標:說明性語句,定義中的 SELECT 語句并不立即執行。語法如下:
EXEC SQL DECLARE <游標名> CURSOR FOR <SELECT 語句>
- 打開游標:執行游標定義中的 SELECT 語句,同時游標處于活動狀態,游標是一個指針,此時指向查詢結果的第一行之前。語法如下:
EXEC SQL OPEN <游標名>
- 推進游標:使用時,游標會推進一行,并把指針指向的行(稱為當前行)中的值取出,送到共享變量中。變量表由逗號分開的共享變量組成。該語句經常用于宿主程序的循環結構中,并借助宿主語言的處理語句逐一處理查詢結果中的一個元組。語法如下:
EXEC SQL FETCH FROM <游標名> INTO <變量表>
- 關閉游標:使用時,關閉游標,不再和查詢結果相聯系。關閉了的游標,可以再次打開,與新的查詢結果相聯系。在游標處于活動狀態時,可以修改和刪除游標指向的元組。語法如下:
EXEC SQL CLOSE <游標名>
示例3. 在C語言中嵌入SQL的查詢,檢索某學生的學習成績,其學號由共享主變量givensno給出,結果放在主變量Sno,Cno,Grade中。如果成績不及格,則刪除該記錄,如果成績為60~69分,則將成績修改為70分,并顯示學生的成績信息(除60分以下的)
#DEFINE NO_MORE_TUPLES !(strcmp(SQLSTATE,"02000"))
void sel()
{EXEC SQL BEGIN DECLARE SECTION; /*說明主變量*/char Msno[4],Mcno[3],givensno[5];int Mgrade;char SQLSTATE[6];
EXEC SQL END DECLARE SECTION;
EXEC SQL DECLARE Scx CURSOR FOR /* 說明游標Scx,將查詢結果與Scx建立聯系*/SELECT Sno,Cno,GradeFROM SCWHERE Sno=:givensno;
EXEC SQL OPEN Scx;
While(1) /* 用循環結構逐條處理結果集中的記錄*/
{EXEC SQL FETCH FROM Scx /* 游標推進一行*/INTO :Msno,:Mcno,:Mgrade; /* 送入主變量,注意每個變量要加分號;*/if (NO_MORE_TUPLES) Break; /* 處理完退出循環*/print("%s,%s,%d\n",sno,cno,g);};if (Mgrade<60) /* 成績<60*/EXEC SQL DELETE FROM SC WHERE CURRENT OF Scx;Else {if (Mgrade < 70) /* 成績<70*/EXEC SQL UPDATE SC SET grade = 70 WHERE CURRENT OF Scx;MGrade = 70}Printf("%s,%s,%d",Msno,Mcno,Mgrade); /*顯示學生記錄*/
EXEC SQL CLOSE Scx; /* 關閉游標*/
};
動態 SQL
動態 SQL 允許程序在運行時構造、提交 SQL 查詢。使用動態 SQL 語句時,還可以改進技術;當預備語句組合而成的 SQL 語句只需執行一次, 那么預備語句可以在程序運行時由用戶輸入才組合起來,但并不執行。
動態 SQL 預備語句格式
EXEC SQL PREPARE <動態SQL語句名> FROM <共享變量或字符串>;
動態 SQL 執行語句格式
EXEC SQL EXECUTE <動態SQL語句名>;
示例4. 動態 SQL 示例
char*query = "UPDATE sc SET Grade = Grade*1.1 WHERE Cno = ?";
EXEC SQL PREPARE dynprog FROM :query;
char cno[5] = "C4";
EXEC SQL EXECUTE dynprog USING :cno;
總結
嵌入式SQL和動態SQL是兩種在應用程序中嵌入和使用SQL語句的方法。它們各自具有一定的優勢和局限性,適用于不同的場景。開發人員應根據應用程序的具體需求選擇合適的方法,并在必要時結合使用這兩種方法,以實現最佳的性能和靈活性。