转帖]PROGRESS编程其实很简单(1-3)
PROGRESS编程其实很简单(1-3)
我可以很负责任的告诉你:Progress编程,其实很简单!
PROGRESS属于4GL数据库语言,没有指针没有类也不用搞什么高级接口等,入门起来简直比吃饭还容易,当然,我还告诉你,精通它其实也很容易!
《PROGRESS编程其实很简单》序列教程,只讨论编程的问题,一切数据库管理方面的知识,可以参见另一序列《精通PROGRESS数据库管理》!
其实,针对这2方面的Manual有好几本书,英文版挺厚的,但是个人觉得,实际上真正常用的也就那么几个,所以恭喜你,8小时以后,你就会成为专家了!当然,Manual毕竟是Manual,要留存,以防有些很偏僻的应用需要检索。
接下来的教程学习,需要有一个实际的Progress编程环境!本教程案例基于HP-UX的Progress 9.1D。
Now go ......
PROGRESS编程其实很简单(一)
一、变量定义。
变量必须在第一次被使用之前定义,可以定义在程序的任何地方!但是通常为了增加程序的可读性,变量定义都放在程序的开始处!以下是变量定义的几个实例:
define variable str01 as string label "DemoString" initial "hello".
def var str02 like str01.
def var dt01 as date extent 5.
def var inte01 as inte format ">>>9".
说明,第一行:
str01 是变量名, 变量名不要与系统关键字重复,字符或者下划线开头,比如strModel,_Model ;
string 表示变量类型,本例指字符型变量,其它类似的比如integer,date,logical等 ;
label 就是后续程序中对变量的描述,比如需要用户输入这个变量值时,系统提示“DemoString" ;
initial 变量的初始值
第二行:
def和var都是简写,def是define的简写,var是variable的简写;PROGRESS支持语法简写,但是初学者最好先写全,后面有经验了再简写。
like和as的不同点是:as后面直接说明变量类型,而like后面跟另外一个变量或者字段。
第三行:
extent 5 ,表示该变量是数组变量。
第四行:
format ">>>9" 变量格式
指定变量的格式一个最大的好处就是预留宽度,这个对变量的输入或者报表的输出都很有用的。
比如年份的宽度一定是4位的,那么你就可以指定格式 format "9999"。
PROGRESS程序每行结束必须有个“.”号!!!
二、注释。
注释就是用/* ... */ ,可以嵌套,比如
/*---注释1
/* 注释2 */
---*/
三、记录的显示。
如果进入PROGRESS编程模式以后连接了数据库,那么直接显示记录的值即可,比如:
for each TABLE_NAME:
display TABLE_NAME.
end.
/*显示TABLE_NAME所有字段所有记录*/
或者:
find first TABLE_NAME.
display TABLE_NAME.
/*显示TABLE_NAME第一条记录所有字段的值*/
通常显示记录值都是采用这2种方式!当然,可以按要求显示特殊的字段,比如:
for each pt_mstr where pt_model begins "E" no-lock break by pt_price:
disp pt_model pt_price.
end.
这个程序看起来真的很容易明白,简单说明:
1、where 后面带条件,比如 = <> <= >= 等等,这种关系符,对数字、日期或者字符串,都适用;
关于条件的几种组合举例:
条件1 and 条件2
( 条件1 or 条件2)and (条件3 or 条件4)
not 条件1
2、no-lock,这是关键字,你只要记住:
如果接下来的程序要对记录进行修改,那么不能加no-lock,如果不要,请加上no-lock;
3、break by ,就是按某个字段排列,默认是按这个字段的升序,如果降序则后面加上 desc,比如:
break by pt_price desc。
如果需要多次排列,那么by几次就可以,比如:
break by pt_price by pt_date
另外一个常用的显示或者更新记录的语句是find!比如:
find pt_mstr where pt_model = "mainboard" no-lock no-error.
find first pt_mstr where pt_price <= 10 no-error.
find last pt_mstr where pt_price <= 10 no-error.
说明:
1、where后面的条件跟for each语句类似;
2、no-lock的作用跟for each的no-lock也是一样的;
3、no-error,通常是find就加上,否则如果不到满足条件的记录,系统会出错误提示;而实际上,通常需要在程序自己判断结果;
4、find first 就是定位第一天满足条件的记录;find last 定位最后一条满足条件的记录;
4、还有一种叫find next,就是定位当前记录的下一条;
5、find 和 find first / find last 不同的是,find后面带的条件,通常是满足TABLE的某个唯一索引。
关于for each 和 find,这章你只要了解到这里就OK了!
四、判断。
判断最简单了,就是一个if 条件 then ... else ...,比如:
if str01 = "cpu" then disp "CPU"
else disp "Not CPU".
当然,这个”条件“可能有很复杂的组合。如果,涉及到的动作比较多,那么做法是用d ... end.,比如
if str01 = "cpu" then d
str01 = "my cpu".
disp "CPU".
end.
else d
str01 = "my memory".
disp "Not CPU".
end.
if 支持嵌套,怎么嵌套?你自己会了!不是吗?
五、循环。
PROGRESS的循环功能实在令人不敢恭维,没有when 没有while,没有loop、for什么的,只有一个repeat!
不过,用好了这个repeat,一样实现任何功能。
通常实现循环的模式:
repeat:
/*处理事务*/
if 条件 then leave. /* 退出循环 */
end.
现在,你试试用find 和 repeat 实现 for each的功能!
六、赋值和计算。
+ - * / ,就是 加 减 乘 除了!比如:
ttl_amoount = ttl_ammount + dtl_amount.
x_a = x_b / x_c.
str_ttl = "I'm" + "sure!".
dt01 = today - 1.
dt01 = 3/22/2005. /* 日期 */
当然,日期和字符串不能做乘法或者除法!
七、其它零星的语法。
显示:display 简写disp
退出编程模式:quit
执行UNIX命令: unix COMMAND
PROGRESS编程其实很简单(二)
PROGRESS程序架构。
PROGRESS启动应用程序,通常都是先启动一个主程序,比如mf.p,这个mf.p做一些全局变量设置,并初始化应用程序菜单。当用户执行菜单功能时,实际上是运行菜单所指定的程序!在这种模式下,PROGRESS的程序一般都不大,结构明了可读性很强,每个程序目的非常明确,但是也要遵循一定的准则,方便以后的阅读和修改。
一、程序扩展名的设定。
.p 主程序(可直接运行,或者编译以后挂主菜单被调用)
.i 子程序(经常使用的执行某一特定功能,或者为了使主程序易于阅读脱离出来)
.v 验证程序
.w Windows的程序(Windows版的Progress支持可视化的组件编程,组件拉一拉放一放,就自动生成.w的文件了)
.r 编译后的程序(菜单调用时,实际上是执行.r的程序)
二、程序的命名规则。
主程序格式: aa + bb + cc + dd.p
其中:
aa --- 系统模块ID
bb --- 系统功能
cc --- 程序类型(mt -维护、iq -查询或者rp -报表等)
dd --- 序列号
子程序格式:通常是 主程序a.i 主程序b.i 这样子
//关于程序的命名,个人觉得也没必要一定要遵循特定格式,一家公司有自己固定的命名方式,容易区分即可;如果是咨询公司或者系统集成公司,则要先了解客户的命名习惯和规则;同理,下面的“程序头”。
三、程序头。
以注释的形式,标明尽可能多的程序相关的信息,比如:程序名(路径,不过路径一般都是企业自己规定好了)、作者、菜单号、功能(菜单标题)、创建日期、修改日志等。至于格式,也就是POSE,爱怎么摆怎么摆,清楚明了即可。但是,在同一家公司,风格应该统一。另外,关于修改日志,个人觉得最好在程序头和程序体,都明显说明一下修改的日期和原因,要点。(注释不记入程序长度,所以不要担心程序太长,:p )
四、维护类程序模板。
注意:为方便说明,注释暂时用“//”,但是在PORGRESS程序里是错误的哈!
define variables.
{mfdtitle.i} //程序头,全局变量定义等,是标准QAD的菜单程序就请加上这个,不要问为什么
form with frame a. //定义格局(包含输入输出)
Mainloop:
repeat:
prompt-for … editing: //通常这里输入主要字段(如果比如订单号,料件名称等)
{mfnp.i} //前后记录显示功能,常用
end.
/* ADD/MODI/DELETE */
assign global…
find …
if not available … //新记录
{mfmsg.i 1 1} //类似mfmsg的子程序,都是信息提示类
create …
assign …
end.
Status = stline{2}.
update go-on (F5 or Ctrl-D) //继续维护剩余字段
if F5 or CTRL-D then d //判断是否按了删除键,一般定义是F5或者Ctrl + D
del-yn = yes.
{mfmsg01.i 11 1 del-yn}
end.
End.
Status input.
五、报表类程序的模板。
{mfdtitle.i}
form definition [selection criteria]
part colon 15 part1 colon 40 label {t001.i}
effdate colon 15 effdate1 colon 40 label {t001.i}
with frame a side-labels width 80.
//以上4行定义用户输入“限制报表输出”的条件,比如生效日期啊什么的
repeat:
if part1 = hi_char then part1 = “”. //如果用户不输任何东西,则默认最大字符或者最小字符,以下类似
if effdate = low_date then effdate = ?.
if effdate1 = hi_date then effdate1 = ?.
data statements [selection criteria]
bcdparm = "".
{mfquoter.i part } //BATCH专用,至今没用过,体会不到好处,哪位帮忙解释一下?
{mfquoter.i part1 }
{mfquoter.i effdate}
{mfquoter.i effdate1 }
{mfselbpr.i “printer” 132} //选择打印机的子程序
if part1 = “” then part1 = hi_char.
if effdate = ? Then effdate = low_date.
if effdate1 = ? Then effdate1 = hi_date.
{mfphead.i or mfphead2.i} //报表头
for each…
display
{mfrpchk.i} or {mfrpexit..i} //报表结束
end.
{mfrtrail.i} or {mftr0801.i} or {mfreset.i} //报表结束、打印结束等
end.
六、查询类程序模板。
这个比报表来得要简单些了:
{mfdtitle.i}
form definition [selection criteria]
with frame a side-labels width 80.
repeat:
data statement [selection criteria] with frame a.
{mfselprt.i “terminal” 80 }
for each [selection criteria]
display …
{mfrpchk.i} (max page)
end.
{mfreset.i} (scroll output)
{mfmsg.i 8 1}
end.
PROGRESS编程其实很简单(三)
这章,重点解释PROGRESS报表的精髓 first-of() & last-of() 。
首先给出本章教程用到的示例信息---demo表的结构和数据。
因为测试环境只连接了一个数据库,所以本文所有对字段的引用都直接写出来而没有特别指明表名,如果是多数据库环境,则需要带表名。
(比如数据库名是dtbl,表名是demo,那么对字段的引用应该是:)
【结构】
【数据】
1、first-of() & last-of()的语法;
先看示例:
for each demo break by :
if first-of() then disp .
end.
/*结果是显示hp和ibm两条记录*/
很明显可以看出来的就是,每个first-of或者last-of对应的字段,必须有for each ... break by来对应它,否则语法错误(即使first-of的字段是索引也会出错)。
比如以下语句会出错:
for each demo no-lock:
if first-of() then disp .
end.
2、函数的功能;
first-of()函数的功能,就是通过break by 对该字段进行排序,然后对该字段相同的记录进行“预览”,当第一次出现时发生!比如,示例中,break by首先对进行排序,这样会出现很多vend是“hp”和“ibm”的记录,当第一次出现“hp”记录和第一次出现“ibm”记录时,各显示一下该vend名称。
last-of()一样,不同的是“最后一次出现时发生”!
请看示例:
for each demo break by
if last-of() then disp demo.
end.
这段程序的结果如下:
通过收货日期和数量等,可以看到,每条记录,都是相同“mdlno”的最后一条
3、应用;
通过以上分析,不知道大家有没有懂的真正的意思呢?
现在如果要实现这样的报表,那又该怎么写程序呢?
对每个mdlno收货进行合计,然后在mdlno的下一行显示合计数,类似这样的结果:
不看答案自己想想看。
参考答案(为方便阅读暂不用accum()函数):
DEF VAR ttl AS DECI.
OUTPUT TO c:.
FOR EACH demo BREAK BY
ttl = ttl + .
PUT SKIP .
IF LAST-OF() THEN d
PUT " 合计" ttl SKIP.
ttl = 0.
END.
END.
OUTPUT CLOSE.
说明:first-of
汇总!
和 last-of 可以对应多个 break by的字段,比如可以先按mdlno汇总,再按 vendor
本文发布于:2024-09-23 12:28:10,感谢您对本站的认可!
本文链接:https://www.17tex.com/fanyi/4944.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |