PowerBuilder中动态SQL的实现

软件世界

每个数据库管理系统(DBMS)都有自己的数据处理语言(DML),所有的DML都基于一种语言──结构化查询语言(SQL)。在整个PowerBuilder中,可以发现许多不同形式的SQL,从最明显的嵌入式SQL到最不明显的DataWindow中都可以发现它们的影子。

一、了解SQL

SQL语句有三种主要类型。第一种是最常见的语句查询(query),即信息请求。第二种是数据修改(data modification)语句,即数据的添加、删除或更新。最后一种类型是系统和事务处理管理语句(如事务的提交、回滚及安全性授权等等)。
这些SQL语句可以直接嵌入到用户的PowerScript中,并且可以像直接由数据库管理员来运行它们一样运行。所有的嵌入式SQL都由一个分号(;)结束,以提示PowerBuilder处理器该语句的特殊性质,而且,如果用户的SQL语句延伸多行的话,用户不必使用续行符号(&)。用户只要按需要自由分行,最后用一个分号终止该语句即可。另外,在嵌入式SQL中(同样也在DataWindow的SQL中)连接变量是前缀为冒号(:),并且可以像其他列或值一样由SQL处理的PowerBuilder变量。
例如下面的嵌入式SQL语句:
SELECT COUNT(books),SUM(sales)
INTO :totalboooks,:sumsales
FORM books
WHERE shopname=:sname;
我们利用PowerBuilder的事务处理对象(transaction object)来控制SQL与DBMS之间的连接;在执行完成后,通过查看事务处理对象的SQLCode特性的值可以知道这次操作是否成功,若其值为0,则表示成功,为100表示无结果,为-1表示出错。

二、熟悉游标

游标(cursor)是PowerBuilder中一个重要概念,它是用于遍历一个多行结果集的对象,在微软的概念中,等同于记录集。我们经常在嵌入式SQL中,查询满足条件的记录,并将它们作为一组结果返回,这里就要用到游标。作为动态SQL的主要应用内容,这里有必要简单介绍游标的基本语句:
1.声明游标
DECLARE cursor_name CURSOR FOR select_statement {USING transaction_object};
2.使用游标
OPEN cursor_name;//执行游标,生成记录集
FETCH cursor_name INTO host_variable_list;//将记录集的第一条记录赋给变量集,记录集指针自动指向下一条记录
CLOSE cursor_name;//关闭游标

三、实现动态SQL

在掌握了嵌入式SQL的基本语法后,下一步就要探讨动态SQL问题。所谓动态SQL是指数据库描述语句(DDL),CREATE TABLE和DROP TABLE,或在开发时不清楚参数和结果的SQL语句。
动态SQL可以分为四类:
1.没有结果集或输入参数的情况,它通常用于执行DDL和其他数据库专用代码,如:
EXECUTE IMMEDIATE "DROP TABLE books" USING SQLCA;
其中引号中的内容是开发者需要执行的命令,这里是从数据库中删除了books这个表。
2.没有结果集但要求参数的情况,这些参数在开发时是未知的,它用于要求运行时定义参数的DDL语句中。例如:
PREPARE SQLSA FROM
"UPDATE books SET sale_date=GetDate() WHERE bookname=? AND emp_id=?"
USING SQLCA;
EXECUTE SQLSA USING:sbookname,:sempid;
其中,SQLSA是PowerBuilder提供的动态数据移动区,用于存储SQL以备以后执行,PREPARE语句用于提供SQLSA准备执行的SQL语句,它所包含的“?”表示在执行时需要提供参数的位置。当执行SQL语句时,字符“?”依次由EXECUTE的USING子句所代表的变量值取代。
3.已知结果集和输入参数的情况,它通常被用来生成一个内部表或带有数据库表中数据的下拉列表框(DDLB)(当然,用DataWindow生成DDLB要简单得多,但DataWindow额外的开销,也是要列入考虑的因素之一)。下面例举这种动态SQL的应用:
String sqltext,sbookname
Int isales
sqltext="SELECT bookname,sales FROM books WHERE emp_id=?"//定义带参数的SQL语句
DECLARE usercursor DYNAMIC CURSOR FOR SQLSA;//声明一个动态游标
PREPARE SQLSA FROM :sqltext USING SQLCA;//将动态SQL语句存储在动态数据移动区SQLSA中
OPEN DYNAMIC usercursor USING :sempid;//提供参数,执行动态游标
Do While SQLCA.SQLCODE=0 //只要游标执行成功,且没有FETCH到结果集尾部,就依次从游标中取值,并加入到两个下拉列表框中。
FETCH usercursor INTO :sbookname,:isales;
ddlb_book_name.additem(trim(sbookname))
ddlb_sales.additem(string(isales))
Loop
其中的DYNAMIC是该动态SQL语句的关键字,sqltext变量中的值是需执行的SQL语句内容,sempid是执行动态游标usercursor时SQL语句所需的变量集(这里只有一个自定义变量),其值作为查询条件用以生成结果集。
4.在输入参数或返回结果集未知的情况下,SQL动态描述区(SQLDA)用于保存有关参数和结果集列的信息,输入参数在DECLARE语句中像第二第三种情况那样用字符“?”设置,实际值是用SetDynamicparm()设置的。例如:
Long count=0,lvalue;
String svalue;
DECLARE usercursor DYNAMIC CURSOR FOR SQLSA;
PREPARE SQLSA FROM "SELECT bookname FORM books WHERE emp_id=?" USING SQLCA;
DESCRIBE SQLSA INTO SQLDA;
SetDynamicparm(SQLDA,1,"zhanghong")//将参数保存在SQLDA中
OPEN DYNAMIC usercursor USING DESCRIPTOR SQLDA;//执行动态游标
FETCH usercursor USING DESCRIPTOR SQLDA;//将结果集保存在SQLDA中
Do While count count++
Choose Case SQLDA.OutParmType[count]
Case TypeLong!
lvalue=SQLDA.GetDynamicNumber(count)
Case TypeString!
svalue=SQLDA.GetDynamicString(count)
End Choose
Loop
总结四种动态SQL,各有其用途,并且它们之间有时可以相互实现。当然,也可用DateWindow来实现相应的SQL操作,但以额外开销为代价,是专业编程人员应该避免的,熟练掌握动态SQL语法,将会使你在PowerBuilder中更加游刃有余。