【PB】動態SQL語句
所謂動態SQL語句是指部分或者整個SQL語句在執行時才能確定,這樣的SQL語句可以用來設計能和使用者進行更好互動的介面。因為引數的確定留給使用者總比程式設計時由開發人員規定死要好得多。另外, PowerBuilder不支援有些SQL語句的嵌入執行,例如Create Table,Drop Table等,需要將這些SQL語句交給DBMS執行,而動態SQL語句都是將SQL語句交給DBMS執行的。這些都是要掌握動態SQL語句的原因。
動態SQL語句有四種類型:
l 既無輸入引數,也無結果集;
l 有輸入引數,但沒有結果集;
l 編譯時已經知道引數和結果集的列;
l 開發程式時尚不知道引數和結果集。
10.2.1 型別一
這種型別的動態SQL語句經常用來執行DDL或者資料庫專用的其他SQL語句。語法格式是:
EXECUTE IMMEDIATE SQLStatement {USING TransactionObject} ;
其中SQLStatement是個字串,其內容是有效的SQL語句;TransactionObject是事務物件名,大括號表示該子句可以省略,省略時使用SQLCA。下面是個建立刪除資料表的例子:
string MySQLMySQL = "drop table employee"
EXECUTE IMMEDIATE :MySQL USING SQLCA;
10.2.2 型別二
執行之前已知引數個數並且沒有返回值時使用這種型別的動態SQL語句。這種型別的動態SQL語句也能夠處理需要在執行時定義引數的資料操作語句。其語法格式為:
PREPARE DynamicStagingArea FROM SQLStatement
{USING TransactionObject} ;
EXECUTE DynamicStagingAreaUSING {ParameterList} ;
其中DynamicStagingArea是個DynamicStagingArea型別的變數,該型別的預設全域性變數是SQLSA;SQLStatement是個String型別的常量或者變數,其內容是有效的SQL語句,SQL語句中使用問號代表所需引數,執行時問號被EXECUTE語句中的USING子句所代表的值取代;TransactionObject是事務物件名,大括號表示該子句可以省略,省略時使用SQLCA;ParameterList是引數列表,可以是變數、常量或者控制元件的屬性,各引數對應於SQLStatement中的問號。動態策略區用於準備SQL語句及所需引數個數,它的屬性在執行時應用程式不能訪問,SQLSA是預設的動態策略區變數。下面是這類動態SQL語句的應用示例,它刪除編號為56的僱員資訊:
Int Emp_id_var = 56
PREPARE SQLSA FROM "DELETE FROM employee WHERE emp_id=?" ;
EXECUTE SQLSA USING :Emp_id_var ;
再如:
Prepare SQLSA from
"Insert inTo employee (emp_id,manager_id) value (?,?)"
execute SQLSA using :ls_EmpId,:sle_manager.text;
10.2.3型別三
這種型別的動態SQL語句的使用頻率可能是僅次於第一種型別,它常用來處理引數個數和結果集在編譯時已知的情況,又分為遊標和儲存過程兩種情況。使用遊標形式的語法與程式中出現的次序為:
DECLARE Cursor DYNAMIC CURSOR FOR DynamicStagingArea ;
PREPARE DynamicStagingArea FROM SQLStatement{USING TransactionObject} ;
OPEN DYNAMIC Cursor{USING ParameterList} ;
FETCH Cursor |INTO HostVariableList} ;
CLOSE Cursor;
使用儲存過程的第三類動態SQL語句的格式和次序與上面的語法形式類似,只是使用EXECUTE語句來代替上面的OPEN語句,其語法格式為:
DECLARE Procedure DYNAMIC PROCEDUREFOR DynamicStagingArea ;
PREPARE DynamicStagingArea FROM SQLStatement
{USING TransactionObject} ;
EXECUTE DYNAMIC Procedure{USING ParameterList} ;
FETCH ProcedureINTO HostVariableList} ;
CLOSE Procedure ;
其中,Cursor和Procedure分別是遊標名和過程名;DynamicStagingArea是動態策略區變數,通常使用系統預定義的全域性變數SQLSA;SQLStatement是個字串(常量或變數均可,變數時變數名前面加上冒號(:)),其內容是有效的SQL語句,並使用問號代表引數;ParameterList是對應於SQLStatement中問號的引數列表;HostVariableList是PowerScript主變數(即在其前面加上冒號的PowerScript變數);TransactionObject是事務物件名,預設時使用SQLCA。
DECLARE語句說明動態遊標或動態過程,PREPARE語句準備動態策略區,OPEN或EXECUTE語句開啟動態遊標或執行動態過程,FETCH語句讀取一行資料,如果需要讀取多行資料,那麼需要反覆執行FETCH語句。最後,CLOSE語句關閉動態遊標或動態過程。FETCH語句和CLOSE語句的用法與上節介紹的方法相同。下面是第三類動態SQL語句的一個應用示例,它得到籍貫是“北京”的僱員:
DECLARE my_cursor DYNAMIC CURSOR FOR SQLSA;
Int Emp_id_var
String SQLstatement,Emp_state_var = "北京"
SQLstatament = "SELECT emp_id FROM employee WHERE emp_state = ?"
PREPARE SQLSA FROM :SQLstatement;
OPEN DYNAMIC my_cursor using :Emp_state_var;
FETCH my_cursor INTO :Emp_id_var;
CLOSE my_cursor;
該示例中省略了必要的SQL語句執行狀態檢查工作,在實際編寫程式時,除DECLARE語句外,執行了其他SQL語句後,都應該檢查事務物件的SQLCode屬性,以判斷SQL語句的執行是否成功。
使用這種型別的動態SQL語句可以建立比較通用的向列表框或者下拉列表框中新增資料的指令碼。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//函式名稱wf_AddItem(dropdownlistbox fo_obj,string fs_SQL)
//引數:fo_obj為下拉列表框,fs_SQL為SQL語句
//返回值:無
//功能:使用引數指定的SQL語句向指定的下拉列表框中新增資料
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
String ls_item
Declare item_cur Dynamic Cursor For SQLSA; //定義動態游標
Prepare SQLSA From :fs_SQL Using SQLCA;
Open Dynamic item_cur; //開啟動態游標
Fetch item_cur InTo :ls_item; //取資料
fo_obj.SetRedraw(False) //禁止下拉列表框重新整理
Do While SQLCA.SQLcode = 0
fo_obj.AddItem(ls_item) //向下拉列表框中新增專案
Fetch item_cur inTo :ls_item;
Loop
fo_obj.SetRedraw(True) //重新整理下拉列表框
Close item_cur; //關閉動態游標
10.2.4 型別四
第四類動態SQL語句最複雜,功能也最強,它能夠處理程式設計時尚不知道引數和結果集的SQL語句。與第三類動態SQL語句相似,第四類動態SQL語句也有兩種形式:一種針對遊標處理,另一種則針對儲存過程而言,區別在於遊標處理時使用OPEN語句而不使用EXECUTE語句,而運用儲存過程時則使用EXECUTE語句但不使用OPEN語句。為節約篇幅,下面一併給出第四類動態SQL語句的語法,其中Cursor針對遊標,Procedure針對儲存過程:
DECLARE Cursor | ProcedureDYNAMIC CURSOR |
PROCEDUREFOR DynamicStagingArea;
PREPARE DynamicStagingArea FROM SQLStatement
{USING TransactionObject};
DESCRIBE DynamicStagingArea INTO DynamicDescriptionArea;
OPEN DYNAMIC CursorUSING DESCRIPTOR DynamicDescriptionArea};
EXECUTE DYNAMIC ProcedureUSING DESCRIPTOR DynamicDescriptionArea;
FETCH Cursor | ProcedureUSING DESCRIPTOR DynamicDescriptionArea;
CLOSE Cursor | Procedure;
其中,Cursor和Procedure分別是遊標名和過程名;DynamicStagingArea是動態策略區變數,通常使用系統預定義的全域性變數SQLSA;SQLStatement是個字串(常量或變數均可,變數時變數名前面加上冒號(:)),其內容是有效的SQL語句,並使用問號代表引數;DynamicDescriptionArea是動態描述區變數,這種型別的變數專門用來描述第四類動態SQL語句中的輸入和輸出引數,通常使用系統預定義的全域性變數SQLDA;TransactionObject是事務物件名,預設時使用SQLCA。第四類動態SQL語句使用了動態描述區物件變數,通過該物件變數的四個屬性NumInputs,InParmType,NumOutputs和OutParmType能夠得到輸入引數個數、輸入引數型別、輸出引數個數和輸出引數型別的資訊,其中InParmType是個陣列,每個元素依次對應於SQL語句中的一個問號;OutParmType也是個陣列,每個元素對應於一個輸出引數。InParmType和OutParmType的資料型別是列舉型別ParmType,其取值範圍為表10-6中“適用的引數型別”欄列出的各個值。
表10-6 得到第四類動態SQL輸出引數的函式
函 數 名 |
適用的引數型別 |
GetDynamicNumber() |
TypeInteger! TypeDecimal! TypeDouble! TypeLong!TypeReal! TypeBoolean! TypeUnsignedInteger! TypeUnsignedLong! |
GetDynamicString() |
TypeString! |
GetDynamicDate() |
TypeDate! |
GetDynamicTime() |
TypeTime! |
GetDynamicDateTime() |
TypeDateTime! |
通過使用該物件變數的函式SetDynamicParm()設定具體的輸入引數值。通過使用表10-6中的物件函式得到輸出引數(實際上就是SQL語句的返回資料)的值,每個函式都針對特定的資料型別。
第四類動態SQL語句語法格式中各語句的執行次序十分重要,只有在前一條語句執行成功時,後一條語句的執行才有意義,因此,除DECLARE語句外,其他語句執行後都應該檢查事務物件的SQLCode屬性,以判斷當前SQL語句的執行是否成功。通過多次呼叫FETCH語句,能夠讀取多條資料,每讀出一條資料後,通常在迴圈語句中使用CHOOSE CASE確定
輸出引數的型別後再用表10-6中的物件函式得到其值。下面是第四類動態SQL語句的一個應用示例,其中省略了實際程式設計中必須具備的檢查事務物件SQLCode屬性的過程(即檢查SQL語句執行是否成功):
String , ls_SqlStatement
Int,li_count = 0
ls_SqlStatement = "SELECT emp_id FROM employee"
Prepare SQLSA From : ls_SqlStatement ;
Describe SQLSA InTo SQLDA ;
Declare my_cursor Dynamic Cursor For SQLSA ;
Open Dynamic my_cursor Using DescripTor SQLDA ;
Fetch my_cursor Using DescripTor SQLDA ;
If SQLCA.Sqlcode = 100 Then
MesasgeBox("提示", "沒有找到指定的資料! ")
Close my_cur;
Return
End If
Do
Li_count ++
//當FETCH語句執行成功時,動態描述區SQLDA中包含了結果集的
//第一行資料,反覆執行FETCH語句即可得到其餘資料。
// SQLDA.NumOutputs中包含了輸出引數的個數。
// SQLDA.OutParmType陣列中包含了各引數的資料型別,
//例如TypeInteger!, 或 TypeString!等
//使用CHOOSE CASE語句針對不同的輸出引數型別呼叫不同的物件函式
//得到相應引數的值。
Choose Case SQLDA.OutParmType[1]
Case TypeString!
Stringvar = GetDynamicString(SQLDA, 1)
Case TypeInteger!
Intvar = GetDynamicNumber(SQLDA, 1)
End Choose
Loop While li_count <> SQLDA.NumOutPuts
Close my_cursor ;