中国计算机报1998年总730期  

用PowerBuilder5.0开发“指标分析系统”

 山东 刘茂诚

  “指标类”查询软件一般情况下都作成图、表、文查询的形式,在表格中描述出具体的数据,在图中形象地作一描述和对比,有的还要用一段文字作为补充说明。笔者在作了大量的分析之后,觉得用PB5和ORACLE7开发“指标分析系统”最为合适,中间还有通过ODBC,调用DBASE(FOXBASE)库的操作,现将开发和应用中的一些体会总结成文,供同行们参考。
  本系统的运行结构呈CLIENT/SERVER型,SERVER为COMPAQ5/166服务器 ,上边安装了UNIX操作系统和ORACLE7数据库。CLIENT端通过HUB、ROUTER(远程接MODEM)与SERVER连接,开发、运行平台和工具是WINDOWS3.1、WIN95、PB5,CLIENT端通过FTP、SQL*NET V2或NFS进网工作。系统总体网络协议为TCP/IP。
  通过该系统可查询到历年的一些指标数据,包括劳资、财务、生产、经营、文教卫生等方面的一些指标信息,并由此数据绘出相应的对比图形,并附有文字说明和历史图片等。查询数据多以动态数据窗口产生,图形的数据是源于数据窗口的。文字说明部分存入ORACLE库中,用MLE(多行编辑器)输入、输出,PB5中的MLE可存放较大的文本文件,突破了PB4中32K的限制,所以,可将大量文字资料存放、查询。一些原始资料,如建筑、生产场地、历史背景图等作成了BMP图片,存入ORACLE库中,查询时调入图形框。

  技术难点及解决的方法

  1.PB5和ORACLE7及其它库的连接
  PB5可通过本身提供的功能和ORACLE7做连接,举例如下:
  (a)和某一数据库作固定连接
  //数据库标识符
  SQLCA.DBMS =″o71″
  //要访问的ORACLE用户
  SQLCA.LogID =″lnzb″
  SQLCA.LogPass =″lnzbpwd″
  SQLCA.UserID =″lnzb″
  //用SQL*NET2和ORACLE库连接
  SQLCA.ServerName=″@ora7″
  Connect using sqlca;
  以上的Script语句描述了和某一台SERVER上的ORACLE库的连接过程。
   (b)和多个ORACLE数据库的活动连接
   所谓活动连接,指的是通过修改参数,PB5可随机地连接于网上的每个ORACLE库,实现方法如下:
  // This script will read all the database values from PB.INI
  SQLCA.DBMS =ProfileString(″PB.INI″,″Database″,″DBMS″, ″ ″)
  SQLCA.Database =ProfileString(″PB.INI″,″Database″,″DataBase″, ″ ″)
  SQLCA.LogID =ProfileString(″PB.INI″,″Database″,″LogID″, ″ ″)
  SQLCA.LogPass =ProfileString(″PB.INI″,″Database″,″LogPassword″, ″ ″)
  SQLCA.ServerName =ProfileString(″PB.INI″,″Database″,″ServerName″, ″ ″)
  SQLCA.UserID =ProfileString(″PB.INI″,″Database″,″UserID″, ″ ″)
  SQLCA.DBPass =ProfileString(″PB.INI″,″Database″,″DatabasePassword″, ″ ″)
  SQLCA.Lock =ProfileString(″PB.INI″,″Database″,″Lock″, ″ ″)
  SQLCA.DbParm =ProfileString(″PB.INI″,″Database″,″DbParm″, ″ ″)
  以上语句在执行过程中,查找可搜索路径中的PB.INI文件,因为要连接的库的一些参数就存放于该文件中。
   举一个PB.INI文件的例子如下:
  [Database]
  DBMS=O71 ORACLE v7.1
  Database=
  UserId=
  DatabasePassword=
  LogPassword=lnzbpsd
  ServerName=@ora7
  LogId=lnzb
  Lock=
  DbParm=
  Prompt=0
  通过修改以上PB.INI中的参数,就可以改变要连接的库和连接方式(比如说用SQL*NET TCP1还是SQL*NET V2等),所以称其为活动连接。
  PB5 也可以通过ODBC和ORACLE库连接,但速度较慢,没必要采用这种方式,不过可以用来和其它库(如:DBASE等)作连接,举一个例子说明PB5调用DBASE库的方法:
  odbcdbf=CREATE TRANSACTION;
  odbcdbf.DBMS = ″ODBC″
  odbcdbf.database = ″″
  odbcdbf.userid = ″public″
  odbcdbf.dbpass = ″″
  odbcdbf.logid = ″″
  odbcdbf.logpass = ″″
  odbcdbf.servername = ″lnzb.dbs″
  odbcdbf.dbparm=″Connectstring='DSN=lnzb.dbs;DBQ=c:\1nzb\dbs;FIL=dBase3;'″
  Connect using odbcdbf;
  上面介绍的是和DBASE库作固定连接的例子,当然也可以作成活动的,将在Configure ODBC中创建和配置好的参数存入参数文件(如:PB.INI)中,通过修改参数,就能够操作多个“目录”下的DBASE库。

  2.灵活使用动态数据窗口

  动态数据窗口指的是在程序的运行过程中通过SQL语句的改变动态地创建、修改数据窗口的内容和表现形式,它多用在对同类型对象的描述过程中,“指标类”的查询软件用动态数据窗口来编制,表现形式一致、构造界面统一、编程效率高,当然还有其它一些优点。
  创建一个数据窗口,并由此绘出图形,动态地创建数据窗口dw_1:

  dw_1.create(syntaxFromSQL(SQLCA, ″SELECT sj,swdz FROM hyscjszb where swdz>0&
  and ytmh='″+rowcha+″' order by sj″,″style=(type=grid)″,err))
  根据dw_1中的数据绘出图形:
  rows = rowcount(dw_1)
  if rows>0 then
  gr_1.SetRedraw(False)
  gr_1.reset(all!)
  gr_1.addseries(″dz1″)
  sum=0
  fromn=mid(getitemstring(dw_1,1,1),1,4)
  endofn=mid(getitemstring(dw_1,rows,1),1,4)
  for i =1 to rows
  xis=mid(getitemstring(dw_1,i,1),3,2)
  yis=getitemnumber(dw_1,i,2)
  if isnull(yis) then
  yis=0
  end if
  sum=sum+yis
  gr_1.adddata(1, yis,xis)
  next
  gr_1.SetRedraw(True)
  st_7.text=string(sum)
  if mc=″21″ or mc=″22″ then
  st_6.visible=false
  st_7.visible=false
  end if
  st_6.text=″累计:″+″(″+fromn+″----″+endofn+″)″
  动态数据窗口的表头部分在建表时或通过修改表结构做好,不然会出现表中的字段名(英文字符)作为表头,不直观。
  小数点位数、显示方式也要在表结构中定义好,不然,动态数据窗口将会用“General”方式显示数据,不会作到小数位数一致和小数点自动对齐等。举一个例子,要想使显示数据自动保留两位小数并使小数点自动对齐,就要在表结构中将“Format”设为 “0.00”。
  数据变量类型的定义:一些整型指标值尽量不要定义成INT类型,因为一旦超过32767就会出错,一定要定义成LONG类型;带小数的指标值要定义成DOUBLE型,若定义成LONG类型,会自动舍去小数部分,出现数据错误。
  自动汇总有关数据项,用EXCEL输出汇总表
  用PB5做正规表的输出不是很方便,但通过PB5,可将数据窗口中的数据生成EXCEL文件簿格式,再通过EXCEL的数据链接,将对应数据调入事先定义好的EXCEL标准输出表中,按用户的要求输出。
  PB5生成EXCEL格式文件的SCRIPT语句举例如下:
  dw_1.SaveAs(″c:\zbfxxt\sj.xls″,excel!,true)
  创建同一坐标内的多条曲线
  string pp
  long i,j
  st_1.text=w_ytktt.ddlb_1.text+″年″+vv+″折线图″
  delete from lzht ;
  commit;
  ni=mid(W_ytktt.ddlb_1.text,3,2)
  for j=1 to 12
  if j<10 then
  ny=ni+″0″+string(j)
  else
  ny=ni+string(j)
  end if
  for i=1 to 5
  if i=1 then
  pp=″折线图1″
  select a84 into :la from lsl_a where x1=:ny and ofn=:ytm;end if
  if i=2 then
  pp=″折线图2″
  select a85 into :la from lsl_a where x1=:ny and ofn=:ytm;end if
  if i=3 then
  pp=″折线图3″
  select a34 into :la from lsl_a where x1=:ny and ofn=:ytm;end if
  if i=4 then
  pp=″折线图4″
  select a31 into :la from lsl_a where x1=:ny and ofn=:ytm;
  end if
  if i=5 then
  pp=″折线图5″
  select a30 into :la from lsl_a where x1=:ny and ofn=:ytm;end if
  insert into lzht(yue,zdm,zdz) values(:j,:pp,:la) using sqlca;
  next
  next
  commit;
  dw_1.SetTransObject(sqlca)
  dw_1.Reset()
  dw_1.Retrieve()

 back.gif (1185 字节)