Oracle dev6i问答

本文档汇集了FORMS开发中的实用技巧,涵盖标题修改、动态下拉列表创建、图像引入等多个方面,帮助开发者提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(说明:本问答来自网络)

 如何改变FORM(FMX模块)运行时的title?
    1、 Developer/2000中FMX默认title为:Developer/2000 Forms Runtime for Windows 95 / NT
    2、 在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
    3、 在此触发器中写如下代码:
    4、 SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW,TITLE,'您的提示');

 

FORM中,怎样创建动态下拉列表List?
1、打开Form Builder
2、文件(F)→新建(N)→表格(F)
3、新建一个非数据块,取名为tool
4、鼠标右键→布局编辑器(E)
5、建一个列表项,名为xl(属于tool块)
6、新建一过程,内写如下的代码

PROCEDURE create_xl IS    

 CURSOR A IS

    SELECT DISTINCT(xl) FROM t_xl;              --建立a游标,从学历档案表取原始数据(有可能动态变化)
 CNT    NUMBER;            --记录总数变量,用于生成列表的总项数
 i           NUMBER;              --循环变量
 TNAME  t_xl.name%TYPE;        --TNAME变量和t_xl表中name项具有相同的结构
BEGIN
 CLEAR_LIST('tool.xl');                --清空列表tool.xl(tool块上的xl项)
 SELECT COUNT(DISTINCT(name)) INTO CNT FROM t_xl;   --计算列表总数
 OPEN A;                              --打开游标
 FOR i IN 1..CNT LOOP                       --开始循环
  FETCH A INTO TNAME;                            --取数
  EXIT WHEN A%NOTFOUND;                       --退出条件
  ADD_LIST_ELEMENT('tool.xl',i,TNAME,TNAME);  --把查询出的值加入列表中(序号,实际值,显示值)
 END LOOP;                       --结束循环
 CLOSE A;                       --关闭游标
END;

7.在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
   在此触发器中写如下代码:create_xl;
   使FORM程序一启动,就调用此过程,达到动态生成下拉列表List的效果。

附:
--学历档案表
create table t_xl(name varchar2(6));
insert into  t_xl values('小学');
insert into  t_xl values('初中');
insert into  t_xl values('职高');
insert into  t_xl values('技校');
insert into  t_xl values('高中');
insert into  t_xl values('中专');
insert into  t_xl values('大专');
insert into  t_xl values('本科');
insert into  t_xl values('研究生');
commit;

FORM中,如何引入图像,制作封面?
1、 打开Form Builder
2、 文件(F)→新建(N)→表格(F)
3、 鼠标右键→布局编辑器(E)
4、 文件(F)→导入(I)→图象(I)
5、 可调入作好的图像,以制作封面。
6、 所支持的图像格式有:TIF、JPG、BMP、TGA、PCX、PCT、GIF、CAL、RAS、OIF、PCD等

运行FORM时,如何使按钮变灰(即无效)?
set_item_property('按钮名称',ENABLED,PROPERTY_FALSE);

 

FORM中,设置应用特性(光标类型)
在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
SET_APPLICATION_PROPERTY(CURSOR_STYLE,'CROSSHAIR'|'BUSY'|'HELP'|'DEFAULT'|'INSERTION');

运行FORM时,如何使窗口(runtime窗口、画布窗口)自动变成最大化、最小化?
1. 在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
2. 在此触发器中写如下代码:
SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW,WINDOW_STATE,MAXIMIZE);--最大化
SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW,WINDOW_STATE,MINIMIZE);--最小化

FORM中,WINDOW标题的设置
1. 在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW, title,'你要写的标题');
或用以下方法
2. 对象导航器→窗口→WINDOW0(窗口的名字)→属性→标题→修改其属性

FORM中,Exception(例外)都有哪些,如何书写?
BEGIN 
《PL/SQL块》;
 Exception
  when no_data_found then --没有找到数据
   《响应命令》;
  when too_many_rows then --返回多行,隐式光标每次只能检索一行数据
   《响应命令》;
  when invalid_number then --字符向数字转换失败
   《响应命令》;
  when zero_divide then  --被零除
   《响应命令》;
  when dup_val_on_index then --向唯一索引中插入重复数据
   《响应命令》;
  when invalid_cursor then --非法游标操作
   《响应命令》;
  when value_error then  --数字的,数据转换,截字符串或强制性的错误
   《响应命令》;
  when others then  --发生其它任何错误
  null;   --选择一:什么也不做,就当错误没发生
  raise form_trigger_failure; --选择二:挂起当前程序
 END;

 如何在FORM运行中,使定制菜单中的“窗口(W)”菜单项不显示?
对象导航器→窗口→WINDOW0(窗口的名字)→属性→模式→修改其属性
  设置窗口属性:模式=是

FORM中,如何屏蔽默认的功能键?
1. 在Form级触发器中添加触发KEY-OTHERS
2. 在此触发器中写如下代码:
    null;
3. 这样FORM程序运行后,大部分的功能键都被屏蔽(包括一些必需键,如:上箭头、下箭头、退出...),
    要想让这些键再恢复功能,就为这些键各自编程:
    按键       触发器       代码        说明
    上箭头       KEY-DOWN       DOWN;        上滚记录
    下箭头       KEY-UP        UP;         下滚记录
    Page Up       KEY-SCRUP       SCROLL_UP;     上翻屏
    Page Down      KEY-SCRDOWN      SCROLL_DOWN;    下翻屏
    F1         KEY-HELP       HELP;        显示帮助
    F3         KEY-DUP-ITEM     DUPLICATE_ITEM;   复制项
    F4         KEY-DUPREC      DUPLICATE_RECORD;  复制记录
    F5         KEY-MENU       BLOCK_MENU;     块导航菜单
    F6         KEY-CREREC      CREATE_RECORD;   插入记录
    F7         KEY-ENTQRY      ENTER_QUERY;    输入查询条件 
    F8         KEY-EXEQRY      EXECUTE_QUERY;   运行查询
    F9         KEY-LISTVAL      LIST_VALUES;    显示LOV
    F10         KEY-COMMIT      COMMIT;       存盘
    Enter、Tab     KEY-NEXT-ITEM     NEXT_ITEM;     下一项
    SHIFT+TAB      KEY-PREV-ITEM     PREVIOUS_ITEM;   前一项
    Ctrl+Q       KEY-EXIT       EXIT_FORM;     退出/取消查询

FORM中,触发子exit_form的两种功能是什么?
1、退出FORM
    exit_form;
2、取消查询
    if :System.Mode = 'ENTER-QUERY' then 
     exit_form;
    end if;

FORM中如何存取图象?如何把图象从一个表中导到另一个表中?
1、SQL*Plus中
 SQL> create table t_photo1(photo1 long raw);
 SQL> create table t_photo2(photo2 long raw);
 2、硬盘上c:/下有一个图象文件tmp.bmp
 3、打开FORM
 新建两个块:t_photo1、t_photo2
 t_photo1块是数据库块,连接的表是数据库中的一个表t_photo1
 t_photo2块也是数据库块,连接的表是数据库中的另一个表t_photo2(备份表)
 t_photo1块上新建一个图象项,名为photo1,对应的是即表t_photo1中的photo1列
 t_photo2块上也新建一个图象项,名为photo2,对应的是即表t_photo2中的photo2列
 新建一按钮1,输入以下程序,这个按钮实现读入图象到表里,即录入图象到表里
BEGIN
  GO_BLOCK('t_photo1');--到块1
  READ_IMAGE_FILE('c:/tmp.bmp','bmp','t_photo1.photo1');
  --读入外部图象文件tmp.bmp(图象类型为BMP)到t_photo1块的photo1项,也就是到了t_photo1表里
  COMMIT;--存盘
 END;
 新建一按钮2,输入以下程序,这个按钮实现图象的倒表(t_photo1到t_photo2)
 BEGIN
  GO_BLOCK('t_photo1');--到块1
  execute_query;
  --查询出表中的图象,这时,表中的图象到了FORM中的图象项上
  WRITE_IMAGE_FILE('c:/tmp.bmp','bmp','t_photo1.photo1');
  --把图象项中图象写入外部图象文件tmp.bmp
  GO_BLOCK('t_photo2');--到块2
  READ_IMAGE_FILE('c:/tmp.bmp','bmp','t_photo2.photo2');
  --把外部图象文件tmp.bmp读入到t_photo2块的photo2项,也就是到了t_photo2表里
  COMMIT;--存盘
 END;

 运行此程序,点击此按钮观察效果。

 注释:t_photo1.photo1是正式图片表中的图象项(数据库项)(t_photo1块photo项1)
       t_photo2.photo2是备份图片表中的图象项(数据库项)(t_photo2块photo项2)

FORM中如何存取声音?
1、 硬盘上c:/下有一个声音文件tmp.wav
2、 打开FORM
 新建一个块:t_sound
 t_sound块上新建一个声音项,名为sound1
 新建一按钮1,输入以下程序
 BEGIN
  GO_ITEM('sound1');
  READ_SOUND_FILE('c:/tmp.wav','wave','sound1');
  PLAY_SOUND('sound1');
 END;
 运行此程序,点击此按钮观察效果。

FORM中,当用鼠标点击标签画布的某一“标签页”时,如何判断点击的是哪一页?
1. 在Form级触发器中添加触发WHEN-TAB-PAGE-CHANGED
 2. 在此触发器中写如下代码:
 DECLARE
  canvas_id   VARCHAR2(30);   --标签页ID
 BEGIN
  canvas_id := GET_CANVAS_PROPERTY('标签画布名', topmost_tab_page);
  IF canvas_id='标签页1'  then go_block('块1');end if;
  IF canvas_id='标签页2'  then go_block('块2');end if;
  IF canvas_id='标签页3'  then go_block('块3');end if;
  execute_query;
 END;
FORM中,常用快捷键有哪些?
 CTRL+S 保存
 CTRL+T 编译文件
 CTRL+R 运行FORM
 CTRL+J 连接
 F1 调用帮助
 F2 布局编辑器
 F4 属性选项板


在DEV6i中利用DDE将数据倒入到EXCEL文件中的方法 
在实际的工作中,经常遇到用户要将EXCEL文件中的数据倒入到ORACLE数据库中,也经常遇到用户要将ORCLE数据库中的数据倒入到EXCEL文件中,这方面的资料并不多见(PB6的这项功能很简单,只需在DATAWINDOW控件中加入dw_1.save()这一函数就可以了),通常的做法是利用DEVELOPER 2000自带的示例进行修改来完成任务,但效果也不好,尤其是对初学者,面对示例中的OLE示例可能如入雾里,我在实际工作中利用DDE将数据倒入到EXCEL文件中,效果也不错,在这里向大家作一介绍. 
所谓DDE,就是动态数据交换,相信各位并不陌生.运用DDE倒数据的先提条件是先在本机安装微软office中的EXCEL,在C:盘上建立一空的EXCEL文件如EXCEL.xls,打开该文件,然后运行自己开发的FORM文件. 
下面我就我工作中遇到的实际工作遵照原意逐步进行介绍: 
先用form4.5(5.0当然更可以)建立一个新FORM,在canvas上的新blok中建一个button,然后在该button中的WHEN-BUTTON-PRESSED触发子中,输入以下代码: 
DECLARE
CROW      varchar2(8);
CCOL1     varchar2(8);
CCOL2      varchar2(8);
CCOL3      varchar2(8);
CCOL4      varchar2(8);
CCOL5      varchar2(8);
CCOL6      varchar2(8);
CCOL7      varchar2(8);
CCOL8      varchar2(8);
CCOL9      varchar2(8);

TEMP    VARCHAR2(8);
ConvID    PLS_INTEGER;

/*该游标c1是用来从ORACLE提取数据,
并将数据倒入到EXCEL文件中的*/
CURSOR C1 IS SELECT 
A.SHIPMENT_NO,A.ARRIVAL_DATE,
B.DELIVERY_REF_1,B.DELIVERY_REF_3,
B.DELIVERY_REF_2,C.CASE_NO,C.LRCM_CODE,
C.ANN_QUANTITY,C.QUANTITY_DESCRIPTION,
C.SPARE_PART,C.TRANSFER_NUMBER,
C.TRANSFER_DATE FROM 
ACM A,ACMCONTRACT B,ACMDELIVERY_PL D,
ACMCASE_PL C
WHERE 
A.SHIPMENT_NO=B.SHIPMENT_NO AND
A.CONTRACT_NO=B.CONTRACT_NO AND
B.DELIVERY_REF_1=D.DELIVERY_REF_1 AND
B.DELIVERY_REF_2=D.DELIVERY_REF_2 AND
B.DELIVERY_REF_3=D.DELIVERY_REF_3 AND
D.DELIVERY_REF_1=C.DELIVERY_REF_1 AND
D.DELIVERY_REF_2=C.DELIVERY_REF_2 AND
D.DELIVERY_REF_3=C.DELIVERY_REF_3 AND
D.CASE_NO=C.CASE_NO AND C.SPARE_PART='SO' AND 
C.TRANSFER_NUMBER IS NOT NULL 
AND C.TRANSFER_DATE IS NOT NULL;

SHIPMENT_NO_TMP           ACM.SHIPMENT_NO%TYPE;
ARRIVAL_DATE_TMP          ACM.ARRIVAL_DATE%TYPE;
DELIVERY_REF_1_TMP        ACMCONTRACT.DELIVERY_REF_1%TYPE;
DELIVERY_REF_3_TMP        ACMCONTRACT.DELIVERY_REF_3%TYPE;
DELIVERY_REF_2_TMP        ACMCONTRACT.DELIVERY_REF_2%TYPE;
CASE_NO_TMP               ACMCASE_PL.CASE_NO%TYPE;
LRCM_CODE_TMP             ACMCASE_PL.LRCM_CODE%TYPE;
ANN_QUANTITY_TMP          ACMCASE_PL.ANN_QUANTITY%TYPE;
QUANTITY_DESCRIPTION_TMP  ACMCASE_PL.QUANTITY
                          _DESCRIPTION%TYPE;
SPARE_PART_TMP            ACMCASE_PL.SPARE_PART%TYPE;
TRANSFER_NUMBER_TMP       ACMCASE_PL.TRANSFER
                          _NUMBER%TYPE;
TRANSFER_DATE_TMP         ACMCASE_PL.TRANSFER
                          _DATE%TYPE;

NCOUNT                    NUMBER;

BEGIN
/*NCOUNT为游标循环的总记数*/

SELECT COUNT(*) INTO NCOUNT 
FROM   ACM A,ACMCONTRACT B,ACMDELIVERY_PL D,
       ACMCASE_PL C
WHERE 
A.SHIPMENT_NO=B.SHIPMENT_NO AND
A.CONTRACT_NO=B.CONTRACT_NO AND
B.DELIVERY_REF_1=D.DELIVERY_REF_1 AND
B.DELIVERY_REF_2=D.DELIVERY_REF_2 AND
B.DELIVERY_REF_3=D.DELIVERY_REF_3 AND
D.DELIVERY_REF_1=C.DELIVERY_REF_1 AND
D.DELIVERY_REF_2=C.DELIVERY_REF_2 AND
D.DELIVERY_REF_3=C.DELIVERY_REF_3 AND
D.CASE_NO=C.CASE_NO AND C.SPARE_PART='SO' AND 
C.TRANSFER_NUMBER IS NOT NULL AND 
C.TRANSFER_DATE IS NOT NULL;

/*  初始化DDE,同EXCEL及文件建立联系,
此时要确保EXCEL将EXCEL.XLS文件打开  */
ConvID := DDE.Initiate('EXCEL', 'C:/excel.xls');

/*  先在EXCEL文件中第一行加入字段名称,
其中DDE.CF_TEXT为文本型数据,1000为1000毫秒  */
    DDE.Poke(ConvID, 'R1C1','船运号', 
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C2','到达日期', 
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C3','包装箱号',
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C4','LRCM号', 
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C5','SO标识', 
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C6','移交单', 
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C7','移交日期',
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C8','移交数量', 
              DDE.CF_TEXT, 1000);
    DDE.Poke(ConvID, 'R1C9','设备材料描述', 
              DDE.CF_TEXT, 1000);

OPEN C1;
FOR i IN 1..NCOUNT LOOP      
 /*循环从此开始*/
FETCH C1 INTO SHIPMENT_NO_TMP,
ARRIVAL_DATE_TMP,DELIVERY_REF_1_TMP,
DELIVERY_REF_3_TMP,DELIVERY_
REF_2_TMP,CASE_NO_TMP,
LRCM_CODE_TMP,ANN_QUANTITY_TMP,
QUANTITY_DESCRIPTION_TMP,SPARE_PART_TMP,
TRANSFER_NUMBER_TMP,TRANSFER_DATE_TMP;
EXIT WHEN C1%NOTFOUND OR C1%NOTFOUND IS NULL;

/*下面是EXCEL.XLS文件的CELL,
如'R2C2'就是第二行第二列*/
    CROW:=I+1;
    CCOL1:='R'||CROW||'C1';
    CCOL2:='R'||CROW||'C2';
    CCOL3:='R'||CROW||'C3';
    CCOL4:='R'||CROW||'C4';
    CCOL5:='R'||CROW||'C5';
    CCOL6:='R'||CROW||'C6';
    CCOL7:='R'||CROW||'C7';
    CCOL8:='R'||CROW||'C8';
    CCOL9:='R'||CROW||'C9';

    TEMP:=ANN_QUANTITY_TMP;   
    /*NUMBER型数据要先转化为varchar型*/

    DDE.Poke(ConvID, CCOL1, SHIPMENT_NO_TMP,
              DDE.CF_TEXT, 2000000000);
/*日期型要用tochar()进行转换*/   
DDE.Poke(ConvID, CCOL2, TO_CHAR(ARRIVAL_DATE_TMP), 
              DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID,CCOL3,DELIVERY_REF_1_TMP
              ||DELIVERY_REF_3_TMP||
                DELIVERY_REF_2_TMP||
CASE_NO_TMP,           DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL4, LRCM_CODE_TMP, DDE.CF_TEXT, 
           2000000000);
DDE.Poke(ConvID, CCOL5, SPARE_PART_TMP, DDE.CF_TEXT, 
           2000000000);
DDE.Poke(ConvID, CCOL6, TRANSFER_NUMBER_TMP, 
 DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL7, TO_CHAR(TRANSFER_DATE_TMP),
 DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL8, TEMP, DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL9, QUANTITY_DESCRIPTION_TMP, 
           DDE.CF_TEXT, 2000000000);

END LOOP;
CLOSE C1;

DDE.Terminate(ConvID); 
/*结束DDE会话,此时数据已经全部倒入到EXCEL文件中了*/
END;
在做好以上工作后, 编译运行该fmx文件, 此时确保打开excel.xls文件,用鼠标点击按钮,然后将焦点移到excel.xls文件中,你就会发现一行行数据正在被倒入到EXCEL文件中,等完成后, 将EXCEL文件保存起来就可以了.

 使用设置菜单项属性及form 数据项属性限制不同用户的访问范围 
---- 一个应用系统往往有不同的用户,比如: 一个劳资系统中,一个用户负责管理职工基本档案部分,另一个用户负责管理职工工资部分,管理职工基本档案的用户对职工档案只有查询的权限而不能有修改的权限。实现上述功能的一个简单的实现办法是: 
---- 设置两个全局变量分别记录用户名和密码,在进入系统时,两个用户分别输入不同的用户名和密码,判断用户名,使SET_MENU_PROPERTY(MENU1,ENABLED,FALSE)语句设置没有查询权限的用户不能访问菜单项'MENU1'。 

 提高表连接的查询速度 
在表连接查询时,常常用下列查询方法查询数据是: 
SELECT  RECORDNO,NAME,AGE 
FROM  表1
WHERE 表1.RECORDNO NOT IN
   (SELECT RECORDNO
    FROM 表2
    WHERE  BIRTHDAY='710618');
笔者发现,如果表1的长度为6000条记录,表2的长度为1000条记录, 则要4分钟才能出结果。原因是使用了比较运算符 NOT IN ,它的逻辑测试速度是最慢的。利用外连接替换NOT IN 运算符,查询时间则缩短为50秒。修改方法如下: 
SELECT  RECORDNO,NAME,AGE 
FROM  表1,表2
WHERE 表1.RECORDNO=表2.RECORDNO(+)
AND  表2.RECORDNO IS NULL
AND  表2.BIRTHDAY(+)='710618';

 利用用库模块实现模块资源共享 
在编程中很多FROM 模块需要共用一个程序单元。ORACLE FORM 4.5提出了库模块的概念。使用库模块建立共享程序单元库,既减少了磁盘占用空间,又增加程序的可维护性。使用库模块共享程序单元的过程是:点击系统菜单的file-new-liberary选项,建立一库模块,在program units节点下增加一程序单元, 写入需共享程序的单元编码, 编译后存盘。当FORM模块需共享时,在模块的Attached Libraries节点下连接库模块(此时屏幕会提示是否要删除路径,用户选择NO)。这样,用户便可在FORM模块中直接使用共享程序单元了。 

易导致查询数据错误的原因 
在执行数据查询时,经常发现查询结果与预想的不同,主要原因是: 
1.使用 SELECT * FROM <表名> WHERE <字段名> LIKE '%' 语句查询不出 <字段名>为NULL的字段。此时需对字段为NULL的情况另外处理。如:SELECT * FROM <表名> WHERE <字段名> LIKE '%' OR <字段名> IS NULL 
2.使用union 字段连接各表时,连接顺序不是按书写的先后顺序,而是按连接表的第一个字段排序。因此,为了使表按预想的顺序连接,需在各表中插入第一字段指定排序序号。 

使用视图组织报表数据简单且易于维护 
ORACLE REPORT2.5提供了多种报表格式,但在报表中定义各种统计信息不仅繁琐而且不利于今后的维护,使用视图预先将各种统计、汇总数据准备好,可以起到事半功倍的作用,一旦数据源有所调整,只需修改后台视图,而不用再改前端程序了。 
表1结构为:  UNIT     NAME  RECORENO   SEX
              办公室    王五     1            男
              财务科    李四     2            女
                ..        ..       ..      ..
1. 首先建立视图对数据进行汇总: 
CREATE VIEW  RYTJ (UNIT, BOY,GIRL) 
AS SELECT UNIT, SUM(DECODE(SEX,'男'
,1,0)) , SUM(DECODE(SEX,'女',1,0) )
FROM  表1;
2. 使用 ORACLE REPORT 2.5 对视图'RYTJ'建立报表。 

给报表加序号的简单办法 
ORACLE REPORT 2.5 没有提供加序号功能,使用下述简单方法可实现给报表自动加序号:在数据模板中, 向查询组中加入一个公式列 CF_XH NUMBER(4), 赋初值为0, 点击[EDIT] 按钮, 插入编码RETURN(:CF_CH+1)。

 用FORMS 实 现ORACLE 数 据 库 与 其 它 数 据 源 数 据 的 交 换 
---- Dev6i 不 能 实 现 同 时 多 数 据 源 的 同 时 连 接, 在 多 系 统 和 异 种 数 据 源 的 操 作 中 功 能 确 实 大 打 折 扣, 虽 然 可 以 用3GL 加ODBC 作 一DLL 应 用 能 实 现, 但 一 般 的 应 用 中 又 有 点 没 用 必 要 作 的 那 么 复 杂。 实 际 上Developer/6i 内 嵌 包TEXT_IO 为 我 们 提 供 了 一 个 更 简 单 的 方 法。 几 乎 所 有 的 数 据 库 或 数 据 库 前 端 开 发 工 具 都 提 供 文 本 文 件 的 操 作, 这 样 我 们 完 全 可 以 用 文 本 文 件 作 为 数 据 交 换 的 通 用 格 式。 下 例 是 在 保 险 业 中 的 一 应 用:( 要 用 到d2kwfile.dll 应 用) 
DECLARE
 filename varchar2(128):=null;
 filenum text_io.file_type;
 linebuf varchar2(100);
 r_temp  temp%rowtype;
BEGIN
 filename:=d2k_file_dialog.show
('请选择缴费工资台帐原文件','c:/','源文件(*.txt)|*.txt|');
  if filename is null then 
   raise form_trigger_failure; end if;
  filenum:=text_io.fopen(filename,'r');
  loop
    BEGIN
      text_io.get_line(filenum,linebuf);
      TEXT_IO.PUT(linebuf);TEXT_IO.NEW_LINE;
      exception when no_data_found then
      exit;
    END;
    BEGIN
    v_temp.l1=substr(linebuf,1,9);
    v_temp.l2:= to_number(substr(linebuf,10,5));
    insert into temp(l1,l2) values (v_temp.l1,v_temp.l2);
      exception when others then 
    END;
 < < end_loop > >
  null;   
  end loop;
END;
 
REPORT  中实现的动态报表( 一 张 表 利 用 多 个QUERY 语 句, 生 成 一 样 格 式 的 多 张 报 表 
---- 在 做 报 表 时 经 常 要 遇 到 类 似 的 报 表 有 多 张 的 情 况, 虽 然 通 过 简 单 的 拷 贝 可 以 减 少 编 程 的 工 作 量, 但 在 后 期 的 维 护 中 却 增 加 了 难 度, 一 张 表 改 完 后 又 改 另 一 张 表, 进 行 大 量 的 重 复 劳 动 不 是 每 个 程 序 员 想 做 的 工 作。 其 实 在REPORT 2。5 中 有 一 很 好 的 功 能 可 能 完 成 这 样 的 工 作。 就 是REPORT 的" 宏" 代 换。 如 下 例: 
    两个表:tab_temp1 (a number,b number,c number)
     tab_temp2 (d number,e number,f number)
---- 作 两 张 报 表, 表 头 一 样, 但 查 询 不 一 样, 分 别 取 自 两 个 表 
1. 建 一 用 户 参 数(user parameters) p_1 类 型 CHAR 长 度 200, 缺 省 值 是 SELECT A,B,C FROM TAB_TEMP 
2. 建 一 查 询(QUERIES), 在 查 询 语 句 中 输 入:&P_1 
3. 生 成 布 局, 可 按 要 求 画 出 报 表。
---- 因 在 查 定 义 中 用 的 是&p_1 定 义, 所 以 可 以 在 运 行 时 动 态 的 给P_1 传 递 能 数 只 要 能 满 足 其 列 名 定 义 即 可, 例 可 用 如 下 语 句 代 入P_1 
SELECT D A,E B,F C FROM TAB_TEMP2
---- 这 样 就 生 成 了 一 个 多 功 能 报 表, 把 编 写REPROT 工 作 从 简 单 的 布 局 编 辑 中 解 脱 出 来, 而 投 入 到 实 质 性 的 工 作SQL 语 句 的 生 成 上 去。

如何屏蔽系统提示信息? 
在运行一个FORM时往往会弹出一些报警器,但提示的并非出错信息,屏蔽这些报警器的方法是将系统变量:SYSTEM.MESSAGE_LEVEL的值设置为’25’。 

在编写PL/SQL代码中使用SELECT语句时如何避免例外发生? 
在使用SELECT语句为某变量赋值时,往往会出?quot;NO_DATA_FOUND"和"TOO_MANY_ROWS"等异常情况,使用SELECT语句分两种情况:第一种情况,判断某表中是否有符合某一条件的记录,这时使用聚组函数MAX就可以避免以上两个例外的发生。其格式:SELECTMAX(列1),MAX(列2)......INTO变量1,变量2......FROM基表WHERE条件,当没有符合条件的数据时,该语句返回空,即变量1,变量2......的值均为空,而不会出现"NO_DATA_FOUND"例外,另外使用聚组函数MAX的同时也就避免了"TOO_MANY_ROWS"例外。第二种情况,SELECT语句中含聚组函数SUM,这时如果使用了GROUPBY和HAVING子句,当没有符合条件的记录时将发生"NO_DATA_FOUND"例外,此时避免例外的办法是:去掉GROUPBY和HAVING子句,将HAVING子句的条件加到WHERE子句中。这样在使用SELECT语句时就不必再额外增加一段处理例外的代码,从而简化的代码的编写。 

 当使用主从块时,如何使从块自动提交? 
在FORM设计时有时需要用到主从块,在主从块录入时每当鼠标从从块移到主块准备录入一条新记录时,总是弹出一报警器,问你是否保存数据,从而影响录入速度,将该报警器去掉的方法是:在过程"CLEAR_ALL_MASTER_DETAILS"中的"CLEAR_BLOCK(ASK_COMMIT)"即清除从块时是否提交改为"CLEAR_BLOCK(DO_COMMIT)",这样从块录完数据再导航到主块录入新记录时,系统将自动提交数据,而不再出现上述提示。

如何减少FORM所占磁盘空间? 
(1)对于块中只用于查询并且无格式限制的项,设置为显示项。 
(2)保存FORM时先断开与数据库的链接,然后在保存。以上两种方法均可减小FORM的大小,尤其是第二种方法更为明显。当硬盘空间较小,或将程序备份到软盘上时,这样作是很有意义的。 

如何使定制菜单的主菜单中WINDOWS项不显示? 
在MAINMENU中建立一个为WINDOWS属性的菜单项,这样主菜单中WINDOWS项就不再显示。

如何使不同布局的报表显示在同一页上? 
复杂的报表往往是由几部分组成,需建立多个查询,而每个查询都对应着一个布局,怎样才能使具有不同布局的报表数据显示在同一页上呢?其方法如下:第一步,首先根据实际报表格式建立第一个查询组的布局,称为布局1,然后依次再建立起其他查询组的布局,分别称为布局2,布局3......。注意:每个布局最外围的单选框不要去掉。第二步,分别为布局2,布局3......建立一个到布局1的定位(ANCHOR),即选中工具栏中的ANCHOR,鼠标单击布局2的单选框,然后按住鼠标左键并拖动鼠标到布局1的单选框上(可以选择上边﹑下边﹑左边或右边),松开鼠标按钮,按此方法再建立布局3,布局4......到布局1的定位。建立定位的作用是使布局2,布局3......相对与布局1的位置保持不变,这样就使具有不同布局的报表数据显示并打印在同一物理页上。

怎样较快的生成FMX文件? 
用RUN命令,一次只能生成一个.FMX文件,如果想生成一批.FMX文件,这样做即麻烦又费时,一个生成.FMX较快的办法是:先打开要运行的.FMB文件,如何按住SHIFT键将这些文件全部选中,在从系统菜单"文件"中选择"ADMINISTRATION"中"GENERATE"即可。 

如何在FORM中同时加入水平与垂直滚动条?
首先,必须将画布类型设置为“堆叠式”画布,其它类型的画布不能显示滚动条。将画布类型设置为“堆叠式”之后,该画布属性选项板的“物理属性”子类会出现“显示水平滚动条”与“显示垂直滚动条”两项内容,将其同时设置为“是”,则可以同时显示水平与垂直滚动条。

如何在告警框内显示message信息?
当使用系统缺省设置,不进行任何设定时,message信息将在FORM窗口的底部以小字显示。如果希望引起用户注意,可以将message信息显示在告警框中。例如,如果用户输入的数据类型错误,则弹出一个告警窗口,并在其中显示message信息:“输入数据类型不符”,这样,可以更加清晰地提醒用户输入有误,并允许用户及时地改正错误。

  在告警框中显示message信息,只需要创建一个警告(alert)与一个ON_ERROR触发器,由于引用的是系统错误信息,所以不需要程序员自己编写捕捉错误并弹出相关警告信息的程序,从而提供了极大的便利。

  在告警框内显示message信息的过程如下所述:

  1. 创建一个只具有一个按钮的警告“general_error_alert”。

  2. 在FORM一级创建ON_ERROR触发器,在出现错误时,将错误代码与信息显示在告警框中,程序如下:

  declare

  v_button number;

  v_message varchar2(255);

  begin

  --将不需要显示的mesage信息屏蔽掉

  if error_code in (0,40100,40400,40401,41051,40350)

  then null;

  else

  --将错误代码与错误信息联系起来

  v_message:=error_type || '-' || to_char(error_code) || ':' || error_text;

   --将错误信息显示为告警信息

  set_alert_property('general_error_alert',alert_message_text,v_message);

  v_button:=show_alert('general_error_alert');

  end if;

  raise form_trigger_failure;

  end;

 如何一次退出所有FORM?
 如果重复调用并打开了多个FORM,希望在点击任何一个FORM选单上的“退出”按钮时同时退出所有的FORM,需要在每一个FORM中设置一个全局变量global.quit_all,同时在选单条上加入一个“退出”按钮,并建立以下触发器:

  1.在每一个FORM上建立WHEN_NEW_FORM_INSTANCE触发器:

  :global.quit_all := 'N';

  2.在每一个FORM上建立WHEN_WINDOW_ACTIVATED触发器:

  if :global.quit_all = 'Y'

  then exit_form;

  end if;

  3.在选单条的“退出”按钮上建立WHEN_BUTTON_PRESSED触发器:

  :global.quit_all := 'Y';

  exit_form;

  注意,要么使用OPEN_FORM打开FORM,要么使用CALL_FORM打开FORM,不能两者混合使用,否则容易发生错误,无法一次退出所有的FORM。

 

如何在FORM与REPORT之间传递参数?
由于FORM与REPORT是两项独立的产品,不可能使用全局变量传递数据,所以它们之间的数据无法共享。如果希望REPORT继承FORM中的一些数据,可以将FORM中的有关数据作为参数,以参数列表的形式传递给REPORT。

  例如,可以根据用户在FORM中的选择,在REPORT中动态生成符合查询条件的数据,方法是将FORM中的查询条件,作为参数传递给REPORT,从而在REPORT中动态生成查询结果。

  在FORM与REPORT之间传递参数的程序如下所示:

  declare

  pl_id ParamList;

  begin

  —获取tmpdep的参数列表值

  pl_id := Get_Parameter_List( 'tmpdep' );

  —如果参数列表pl_id已存在,则删除它,然后重建。如果不删除当前pl_id,则无法创建参数列表,并在运行FORM时出现错误提示:参数列表已存在,无法重建

  if Not Id_Null( pl_id )

  then Destroy_Parameter_List(pl_id);

  end if;

  --创建参数列表tmpdep

  pl_id:=Create_Parameter_List('tmpdep' );

  --在参数列表pl_id中加入参数w_clause,同时对w_clause赋值

  where deptno=:dept_deptno。

  Add_Parameter( pl_id,'w_clause', TEXT_Parameter, 'where deptno=:dept.deptno');

  --运行报表,并将现有参数列表pl_id与值传递给报表report1

  run_product(reports,'C:/report/report1',synchronous,runtime,filesystem,pl_id);

  end ;

从FORM调用REPORT时,如何使REPORT以满屏方式显示?
当从FORM调用REPORT时,REPORT将按缺省窗口大小(420×360)显示,如果希望REPORT以满屏方式显示,需要加入如下代码:

  add_parameter(pl_id,maximize',TEXT_PARAMETER,'yes');

如何关闭REPORT运行时的参数窗口?
 当FORM调用REPORT时,首先会弹出一个参数窗口,显示所有FORM传递给REPORT的参数,待点击该窗口中的“运行”后,才运行REPORT。我们也可以不显示该参数窗口,方法是在FORM中加入如下代码:

  Add_Parameter(pl_id,'w_clause',TEXT_Parameter,'NO');

在Oracle中实现报表的定长输出
Oracle*Reports是Oracle的数据统计及图形化报表工具,它提供了六种风格的报表格式,而我们通常使用的只有其中的两种,即Tabular和Matrix,无论用哪种风格生成的报表,打印出的表格数都是动态变化的。其中Tabular风格的报表,列数固定,而行数不定;Matrix风格的报表,行数和列数均不定。那么在Oracle*Reports中如何实现报表的定长与定宽输出呢?笔者在实际开发过程中对上述两种风格的报表各总结出一种行之有效的方法,供大家参考。
1. 对于Tabular风格的报表,可用报表触发子After Parameter Form和After Report实现定长输出。其方法是:根据实际情况确定每页打印的行数,当最后一页的记录数少于每页打印的行数时,则用空记录补齐。在触发子After Parameter Form插入空记录,在触发子After Report中再将空记录删除,下面举例说明。
假设有一数据基表WZDM:存放物资代码信息,其数据结构为:
字段名 含义 长度 类型 
wzdm 物资代码 9 c 
wzmc 物资名称 20 c 
xhgg 型号规格 20 c
jldw 计量单位 6 c

要求:按定长输出物资代码表,并且每页均输出x行(x可根据实际情况而定)。
1. 启动Oracle*Reports,建立物资代码打印报表(略),然后在报表触发子After Parameter Form中加入以下代码:
Declare
v—jls number(2);
i number(2):=1;
Begin
Select Count(*) Into V—jls From Wzdm;
If Mod(V—jls,x)〈〉0 Then
  Loop
  Exit When i〉=(x-mod(v—jls,x))+1;
  Insert Into Wzdm(Wzdm,Wzmc,Xhgg,Jldw)
  Values(′′,′′,′′,′′);
  i:=i+1;
  End Loop;
  Commit;
End If;
End;
在报表触发子After Report中分别加入以下代码:
Begin
Delete From Wzdm Where Wzdm Is Null;
Commit;
End;
2. 运行报表后即可输出定长的物资代码表。
说明:对于其它Tabular风格的报表,在编写上述两个触发子时只需将基表名与列名根据实际情况修改一下,并确定x的值即可。
二、对于Matrix风格的报表,可利用视图实现定长与定宽输出,其思路是:当行记录数和列记录少于实际报表的行数和列数时,均以空记录补齐。下面举例说明。
假设有一物资资金消耗去向统计月报,该表横向显示本期消耗去向,纵向显示物资类别,由于每月物资消耗去向和消耗物资均不定,所以此类报表即为一矩阵报表。该报表的数据存放在基表T—ZJXHQX中,其数据结构如下:
字段名 含义 长度 类型 
lbmc 类别名称 20 c 
dwmc 单位名称 20 c
je 金额 14,2 n
要求:按定长定宽输出物资资金消耗去向统计月报,并且每页均输出x行y列(行数和列数可根据实际情况而定)。
1. 首先建一基表T—kjl,用来存放空记录,其数据结构为:
字段名 含义 长度 类型 
no 序号 2 n
建完该数据表后,再往其中插入记录,记录数可根据实际情况而定,一般为一页所能打印的最大行数,这里假设为z条,即No的值为1,2,3…z。
2. 建视图,其过程如下:
Create View V—TJBB As
 Select Dwmc,Lbmc,Je From T—zjxhqx
 Union
 Select Dwmc,Null,To—Number(Null) From T—zjxhqx,T—kjl 
 Where No-(z-x)〉(Select Mod(Count(Distinct Lbmc)-1,x)+1 From T—zjxhqx)
 Union
 Select Null,Lbmc,To—Number(Null) From T—zjxhqx,T—kjl 
 Where No-(z-y)〉(Select Mod(Count(Distinct Dwmc)-1,y)+1 From T—zjxhqx); 
3. 启动Oracle*Reports,建立矩阵报表查询时直接引用视图V—TJBB即可。这样运行时输出的报表每页都是x行y列,即实现了定长和定宽输出。

数字分金额转成大写汉字元金额程序! 
CREATE OR REPLACE FUNCTION CONVERT_MONEY(INPUT_NBR IN NUMBER DEFAULT 0) 
RETURN VARCHAR2 IS
  INPUT_NBR_BAK     NUMBER(20);      /*用于接收输入参数 INPUT_NBR */
  NUM_CHARACTER     VARCHAR2(20) := '零壹贰叁肆伍陆柒捌玖';
  UNIT_CHARACTER    VARCHAR2(40) := '分角圆拾佰仟万拾佰仟亿拾佰仟万拾佰仟亿';
  OUTPUT_STRING     VARCHAR2(100):= '';
  REMAIN_NBR        NUMBER(20);
  BIT_NUM           NUMBER(20);      /*每一位上的数字*/
  BIT_UNIT          VARCHAR2(2);     /*每一位所对的单位*/
  BIT_INDIC         NUMBER(1) :=0;   /*每一位的数字是否为0,0表示为0,1表示不为0*/
  I                 NUMBER(2) :=0;   /*循环次数,索引变量从0开始*/
  SPE_UNIT          VARCHAR2(2):='A';/*特殊位,包括万和亿,表示该亿汉字是否已写入结果字串*/
  SIGN_INDIC        VARCHAR2(1);     /*用于标志数值符号:0为正,1为负*/
BEGIN
  IF     INPUT_NBR=0 THEN RETURN '零圆整';
  ELSIF  INPUT_NBR>0 THEN SIGN_INDIC:='0';
         INPUT_NBR_BAK:=INPUT_NBR;
  ELSIF  INPUT_NBR<0 THEN SIGN_INDIC:='1';
         INPUT_NBR_BAK:=-INPUT_NBR;
  END    IF;

  LOOP
    REMAIN_NBR     := FLOOR(INPUT_NBR_BAK / 10);          /*取出除后的商*/
    BIT_NUM        := INPUT_NBR_BAK - REMAIN_NBR * 10;    /*取出当前位的数值*/
    INPUT_NBR_BAK  := REMAIN_NBR;                         /*保存商以做下一次循环*/
    BIT_UNIT       := RTRIM(SUBSTR(UNIT_CHARACTER, I * 2+ 1, 2));/*取出当前位的单位汉字*/
   
    IF    BIT_NUM > 0 THEN                                /*当前位的值不为0*/
      BIT_INDIC :=1;
      IF    I=6  OR I=14  THEN                        /*当前位是'万'位或'万亿'位*/
            SPE_UNIT:='万';                           /*表示万已经写入OUTPUT_STRING中,在BIT_UNIT中会包含万字*/
      ELSIF (I>=7 AND I<=9) OR (I>=15 AND I<=17) THEN /*当前位在万及千万之间或万亿及千万亿之间*/
            IF   SPE_UNIT!='万' THEN                  /*万还没写入OUTPUT_STRING中,则要写入一次*/
                 OUTPUT_STRING:='万'||OUTPUT_STRING;
                 SPE_UNIT:='万';                      /*表示万已经写入OUTPUT_STRING中*/
            END  IF;
      END   IF;                                       /*高于千万亿的数本程序不考虑了*/

      OUTPUT_STRING := SUBSTR(NUM_CHARACTER, BIT_NUM * 2 + 1, 2)||BIT_UNIT||OUTPUT_STRING;
    ELSE                                      /*当前位等于0时,走此分支*/
      IF   BIT_INDIC = 1 THEN             /*当前位的前一位不为0时写 零 */
           OUTPUT_STRING := '零'||OUTPUT_STRING;
      END  IF;
      IF    BIT_UNIT IN ('圆','亿') THEN  /*若已达圆位,则圆是必须出现的,由于亿太大,不与万相同处理,所以就与圆一样处理*/
            SPE_UNIT:=BIT_UNIT;           /*保存圆与亿,以与万相区别*/
            OUTPUT_STRING := BIT_UNIT||OUTPUT_STRING;
      END   IF;
      BIT_INDIC  :=0;                     /*当前位的值为0*/
    END   IF;

    I := I + 1;
    EXIT WHEN INPUT_NBR_BAK = 0;
  END LOOP;
 
  IF    MOD(INPUT_NBR,10)=0 THEN             /*输入的数字没有分,最小的是角,则尾部串个整*/
    OUTPUT_STRING:=OUTPUT_STRING||'整';
  END   IF;
  IF    SIGN_INDIC='1' THEN
    OUTPUT_STRING:='负'||OUTPUT_STRING;
  END   IF;

  RETURN OUTPUT_STRING;
END;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值