所谓动态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 ;