在powerbuilder中使用动态sql

来源:互联网 发布:神奇陆夫人知乎 编辑:程序博客网 时间:2024/05/09 08:02

     
  powerbuilder是客户/服务器体系结构下的客户端的开发工具,用于开发客户应用程序。powerbuilder支持所有的sql语句,特别是支持动态sql语句,这为开发中处理复杂的任务提供了方便。  
   
  一、动态sql的基础知识    
   
  我们经常使用的sql语句大多都是静态的,也就是说,sql语句的结构是固定的,当编译script时,整个sql语句都是已知的,它们不能在运行时动态的改变。但是,在很多情况下,sql语句或sql所带的参数在编译时并不知道,应用必须在运行时才能生成sql语句。这种在运行时才能生成的sql语句叫动态sql语句。动态sql允许应用程序向数据库发送任何查询。此外,某些类型的操作,尤其是数据定义语言的语句如create和   drop等,对嵌入式sql根本就不可能。动态sql使得可以象发送查询一样向数据库发送ddl和数据存取语言的语句。  
   
  为了支持动态sql,powerbuilder提供了两种数据类型:dynamicstagingarea   和dynamicdescriptionarea。powerbuilder使用dynamicstagingarea类型的变量为后续语句保存信息,用作语句的运行和事物对象之间的连接。dynamicstagingarea类型的变量是powerbuilder内部使用的,用户无法访问dynamicstagingarea中的信息。powerbuilder提供了一个全局的dynamicstagingarea变量,变量名为sqlsa,当需要一个dynamicstagingarea变量时可以使用它。用户也可以根据需要定义并创建另外的dynamicstagingarea类型的变量。下面的例子定义并创建了一个dynamicstagingarea类型的变量,变量名是dsa_stage1。  
   
            dynamicstagingarea   dsa_stage1  
   
            dsa_stage1=create   dynamicstagingarea  
   
  powerbuilder使用dynamicdescriptionarea类型的变量保存动态sql语句中的输入和输出参数的信息。powerbuilder也提供了一个全局的dynamicdescriptionarea变量,变量名为sqlda,当需要一个dynamicdescriptionarea变量时可以使用它。用户也可以根据需要定义并创建另外的dynamicdescriptionarea类型的变量。下面的例子定义并创建了一个dynamicdescriptionarea类型的变量,变量名是dda_desc1。  
   
            dynamicdescriptionarea   dda_desc1  
   
            dda_desc1=create   dynamicdescriptionarea  
   
  为适应所有的sql语句,powerbuilder根据语句的类型和未知数的个数把动态sql分为四种不同的格式。下面将详细介绍动态sql的这四种格式。  
   
  二、动态sql格式一    
   
          使用这种格式执行的sql语句不会产生结果集,并且不需要输入参数。可以使用这种格式执行所有的数据定义语言。语法如下:  
   
          execute   immediate   sqlstatement     {   using   transactionobject   }  
   
          其中,sqlstatement是包括合法sql语句的字符串,该字符串必须放在一行上,并且不能包含表达式。它可以是字符串常量或前面带有冒号的powerbuilder字符串变量。transactionobject是指向数据库的事物对象名。此方法成立的前提是:1、用于除select之外的sql语句。2、在sql语句中不能包含变量。  
   
  例如,下面语句创建一个名为   auths的表,它用串ls_sql存放sql语句。  
   
  string   ls_sql  
   
  //若与sql   server、sybase   11、odbc数据库相连,在运行create前,  
   
  //必须置系统对象属性autocommit为true  
   
  sqlca.autocommit=true  
   
  ls_sql="create   table   auths(auths_id   char(6)   not   null,"+&  
   
              "auths_name   char(10)   not   null,auths_phone   char(12),"+&  
   
              "auths_address   char(50),primary   key(auths_id))"  
   
  execute   immediate     :ls_sql     using   sqlca;  
   
  sqlca.autocommit=false  
   
          注意:在给出的sql语句串的结束位置不能加“;”号。  
   
  使用格式一的动态sql语句适合于在程序运行期间,创建一些简单的临时的数据库对象来保存数据等,做一些程序运行的辅助性工作。  
   
  三、动态sql格式二    
   
  使用这种格式执行的sql语句不产生结果集,但是需要输入参数。使用这种格式可以执行所有形式的数据定义语言。语法如下:  
   
          prepare   dynamicstagingarea   from   sqlstatement   {   using   transactionobject   }  
   
          execute     dynamicstagingarea     using   {parameterlist   }  
   
          其中,dynamicstagingarea是dynamicstagingarea变量名。sqlstatement和transactionobject的意义同格式一。parameterlist是逗号分隔的一组powerscript变量表,在它们的前面要有冒号。此方法成立的前提是:1、用于除select之外的sql语句。2、在sql语句中可用变量,但必须预先说明。  
   
  例如,下面语句在sqlsa中准备了一个带有一个参数的delete语句,然后把变量author_code的值带入并运行它:  
   
  string     sl_sql,author_code  
   
  sl.sql="delete   from   auths   where   auths_id=?"  
   
  prepare   sqlsa   from   :ls_sql   using   sqlca;  
   
  author_code=a00001  
   
          execute   sqlsa   using   :author_code;  
   
          格式二可用于执行除select语句之外的其它任意sql语句,由于可以输入参数,因此,它可以灵活地控制sql语句的执行条件。  
   
  四、动态sql格式三    
   
  使用这种格式执行的sql语句产生结果集,也需要输入参数,但结果集中列的数目必须固定。使用这种格式的语法如下:  
   
  declare   cursor   |   procedure  
   
                      dynamic   cursor   |   procedure   for   dynamicstagingarea;  
   
  prepare     dynamicstagingarea     from   sqlstatement  
   
                      {   using   transactionobject   };  
   
  open     dynamic     cursor   {   using   parameterlist   };  
   
  execute     dynamic     procedure     {   using   parameterlist   };  
   
  fetch     cursor   |   procedure     into   hostvariblelist   ;  
   
  close   cursor   |   procedure   ;  
   
          其中,cursor或procedure   是要使用的游标或过程名;dynamicstagingarea、sqlstatement、transactionobject和parameterlist的意义同格式二。hostvariblelist是存放查询结果的powerbuilder变量。此方法成立的前提是:1、用于动态的select语句,但select语句中列的数目必须固定,where、order   by等子句可任意合成。2、在sql语句中可用变量,但必须预先说明。  
   
  例如,下面语句在ls_sql中准备一个查询auths表的select语句,把查询结果返回给powerbuilder变量:  
   
  string   name,ls_sql,code      
   
  code="a%"                              
   
  ls_sql="select   auths_name   from   auths   where   auths_id   like   ?"  
   
  declare   c1   dynamic   cursor   for   sqlsa;  
   
  prepare   sqlsa   from   :ls_sql;  
   
  open   dynamic   c1   using   :code;  
   
  lable:  
   
  fetch   c1   into   :name;  
   
  if   sqlca.sqlcode=0   then       //如果成功取出记录  
   
        //进行相应处理  
   
        goto   lable                               //取下一条  
   
  end   if  
   
  close   c1;                                   //关闭游标  
   
          格式三可用于执行where、order   by   等子句任意组合的select语句。  
   
 

发表者:ice2water
五、动态sql   格式四    
   
  这是一种全动态的sql   语句。全动态的sql   语句是指这样的语句:在写程序时并不知道select语句的选择项是什么或有多少个,也不知道sql语句中包含了多少个变量,它们是变化的。全动态sql支持临时生成的sql。全动态sql实现起来很复杂,也很有用,下面我们将详细讲述。语法如下:  
   
  declare   cursor   |   procedure  
   
                        dynamic   cursor   |   procedure   for   dynamicstagingarea;  
   
  prepare     dynamicstagingarea     from   sqlstatement  
   
                        {   using   transactionobject   };  
   
  describe   dynamicstagingarea   into   dynamicdescriptionarea;  
   
  open   dynamic   cursor   |   procedure  
   
                        using   description   dynamicdescriptionarea;  
   
  execute     dynamic     cursor   |   procedure  
   
                        using   description   dynamicdescriptionarea;  
   
  fetch     cursor   |   procedure     using   description   dynamicdescriptionarea;  
   
  close     cursor   |   procedure   ;  
   
  其中,cursor或procedure   是要使用的游标或过程名;dynamicstagingarea是dynamicstagingarea变量名;sqlstatement   是包含合法sql语句的字符串,它可以是字符串常量或前面带有冒号的powerbuilder字符串变量,它必须包含在一行且不能包括表达式;transactionobject是指向数据库的事物对象名。dynamicdescriptionarea   是dynamicdescriptionarea   变量名。  
   
            可以用以下方法设置在prepare语句中出现的每个输入参数的类型和值。powerbuilder在   describe运行时可取得sqlda的属性numinputs和inparmtype,可用这些值和函数setdynamicparm给输入参数的类型和值赋值。输入参数是任选的,若要使用它们,应在运行open或execute语句之前给它们赋值。  
   
            可以用以下方法取得prepare语句中的每个输出参数的类型和值。如果使用的数据库支持输出参数描述,powerbuilder应用可在describe语句执行时取得sqlda的numoutputs值;若数据库不支持输出参数描述,powerbuilder应用可在fetch语句执行时取得sqlda的numoutputs值。可用输出参数的号码从输出参数类型数组中获得特定参数的类型。得到类型后,在fetch语句后可调用恰当的函数取出输出值。  
   
          下面是一个使用动态sql格式四的例子,此例有一个字符串输入参数,但输出参数的类型和个数不定。  
   
          string   ls_sql,ls_val  
   
          integer   i,li_boolean  
   
          ls_sql="select   *   from   auths   where   auths_id=?"  
   
          declare   c1   dynamic   cursor   for   sqlsa;    
   
          prepare   sqlsa   from   :ls_sql;  
   
          describe   sqlsa   into   sqlda;  
   
          //若describe成功,则输入描述符数组将包含一个输入描述符,    
   
          //在打开游标前必须先给输入描述符赋值。    
   
          setdynamicparm(sqlda,1,a00001)           //这里的“1”表示第一个参数    
   
          open   dynamic   c1   using   descriptor   sqlda;    
   
          lable:    
   
          fetch   c1   using   descriptor   sqlda;    
   
          if   sqlca.sqlcode=0   then   //若fetch成功    
   
            for   i=1   to   sqlda.numoutputs      
   
                  //sqlda.numoutputs含有输出参数的个数    
   
                  choose   case   sqlda.outparmtype[i]    
   
                  case   typestring!    
   
                            ls_val=getdynamicstring(sqlda,i)    
   
                  case   typedate!    
   
                            ls_val=string(getdynamicdate(sqlda,i),dd   mm   yyyy)    
   
                  case   typetime!    
   
                            ls_val=string(getdynamictime(sqlda,i),hh:mm:ss)    
   
                  case   typedatatime!    
   
                            ls_val=string(getdynamicdatetime(sqlda,i),&    
   
                                                          dd   mm   yyyy   hh:mm:ss)    
   
                  case   typeinteger!,typelong!,typedecimal!,typedouble!,typereal!    
   
                            ls_val=string(getdynamicnumber(sqlda,i))    
   
                  case   typeboolean!    
   
                            li_boolean=getdynamicnumber(sqlda,i)    
   
                            if   li_boolean=1   then    
   
                                  ls_val="true"    
   
                            else    
   
                                  ls_val="false"    
   
                            end   if  
   
                  end   choose  
   
                  ……   //进行相应处理  
   
            next  
   
            goto   lable     //取下一条记录  
   
            enf   if  
   
            close   c1;  
   
            格式四适合于所有子句都不确定的select语句,这是最有用的一种动态sql。    
   
  六、使用动态sql的一个实例  
   
     
         
   
          下面我们介绍一个用于单表单查询条件生成的通用窗口的实现,在该窗口的实现中使用了动态sql格式四。    
   
         
   
          该窗口是一个响应式窗口,在调用该窗口时传递所要查询的表名给此窗口,在字段名下拉列表框中显示出此表中的所有字段,选定字段名后,在数值下拉列表框中显示出选定字段的内容,按“确定”按钮,生成查询条件并返回。下面是源代码。  
   
  1、定义窗口的实例变量:  
   
  string     tablename       //用于存放表名  
   
  string     s_field             //用于存放选择的字段名  
   
  string     typename         //用于存放所选字段的数据类型  
   
          2、窗口open事件中的脚本:  
   
  tablename=message.stringparm  
   
  //定义cursor将表名为tablename的所有列从系统表“pbcatcol”中取出,  
   
  //并显示在下拉列表框中  
   
  int   i  
   
  string   str  
   
  declare   c1   cursor   for   select   pbc_hdr   from   pbcatcol  
   
                  where   pbc_tnam=:tablename;  
   
  open   c1;  
   
  fetch   c1   into   :str;  
   
  do   while   sqlca.sqlcode=0  
   
                ddlb_1.additem(str)  
   
                i=i+1  
   
                fetch   c1   into   :str;  
   
  loop  
   
  close   c1;  
   
          3、字段名下拉列表框selectchanged事件中的脚本:  
   
  string   s_ddlbtext,sql  
   
  s_ddlbtext=string(ddlb_1.text)  
   
  select   pbc_cnam     into   :s_field   from   pbcatcol      
   
        where   pbc_tnam=:tablename   and   pbc_hdr=:s_ddlbtext;  
   
  ddlb_2.reset()  
   
  //定义cursor将字段名为s_field的字段值从表“tablename”中取出,  
   
  //并显示在下拉列表框中  
   
  string   str  
   
  sql="select   distinct   "+s_field+"   from   "+tablename  
   
  prepare   sqlsa   from   :sql;  
   
  describe   sqlsa   into   sqlda;  
   
  declare   c1   dynamic   cursor   for   sqlsa;  
   
  open   dynamic   c1   using   descriptor   sqlda;  
   
  if   sqlca.sqlcode<0   then  
   
                messagebox("提示信息","动态游标无法执行!"+sqlca.sqlerrtext)  
   
                return   sqlca.sqlcode  
   
  end   if  
   
  lab1:  
   
    fetch   c1   using   descriptor   sqlda;  
   
    if   sqlca.sqlcode=0   then  
   
                              choose   case   sqlda.outparmtype[1]  
   
                                            case   typestring!  
   
                                                          typename="string"  
   
                                                          str=getdynamicstring(sqlda,1)  
   
                                            case   typedate!  
   
                                                          typename="date"  
   
                                                          str=string(getdynamicdate(sqlda,1),"yyyy-mm-dd")  
   
                                            case   else  
   
                                                          typename="number"  
   
                                                          str=string(getdynamicnumber(sqlda,1))  
   
                              end   choose  
   
                              ddlb_2.additem(str)  
   
        goto   lab1  
   
  end   if  
   
  close   c1;  
   
          4、命令按钮“确定”的clicked事件的脚本:  
   
  string   wheresql  
   
  if   string(ddlb_1.text)<>""   and   string(ddlb_2.text)<>""   &  
   
        and   string(ddlb_3.text)<>""   then  
   
                choose   case   typename  
   
                case   "string"  
   
                              wheresql=s_field+"   "+ddlb_3.text+"   "+string(ddlb_2.text)+""  
   
                case   "date"  
   
                              wheresql=s_field+"   "+ddlb_3.text+"   date("+string(ddlb_2.text)+")"  
   
        case   "number"  
   
                              wheresql=s_field+"   "+ddlb_3.text+"   "+ddlb_2.text  
   
        end   choose  
   
                closewithreturn(parent,wheresql)  
   
  else  
   
                messagebox("提示信息","请正确输入字段名、运算符和数值!")  
   
                return   1  
   
  end   if  

 

原创粉丝点击