千家信息网

APP_CALCULATE.RUNNING_TOTAL用法

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,有时候需要显示某个栏位的汇总数量,且在例如新增、删除、修改记录的时候,汇总项的值要相应地改变,如果直接使用Form中的SUM属性功能,对于清除等操作要进行复杂处理。Oracle提供了APP_CALCU
千家信息网最后更新 2026年11月02日APP_CALCULATE.RUNNING_TOTAL用法

有时候需要显示某个栏位的汇总数量,且在例如新增、删除、修改记录的时候,汇总项的值要相应地改变,如果直接使用Form中的SUM属性功能,对于清除等操作要进行复杂处理。Oracle提供了APP_CALCULATE.RUNNING_TOTAL来实现这种需求,封装在APPCORE.PLL中。

For Example:
要汇总的ITEM为:LINES.QUANTITY,要显示汇总结果的BLOCK为HEADERS
1.HEADERS里建立要显示的汇总结果ITEM,如QTY_SUM
2.HEADERS里建立两个非数据库项,分别命名为QTY_SUM_RTOT_OLD和QTY_SUM_RTOT_DB(Number型)
3.LINES里建立两个非数据库项,分别命名为QUANTITY_RTOT_OLD和QUANTITY_RTOT_DB(Number型)
4.建立存储过程来包装APP_CALCULATE.RUNNING_TOTAL
例:
PROCEDURE RUNNING_TOTAL_QUANTITY(EVENT VARCHAR2) IS
BEGIN
APP_CALCULATE.RUNNING_TOTAL(EVENT, 'LINES.QUANTITY', 'HEADERS.QTY_SUM');
END;
--在TRIGGER中调用RUNNING_TOTAL_QUANTITY来进行计算处理
5.:LINES.QUANTITY的WHEN-VALIDATE-ITEM Trigger中写RUNNING_TOTAL_QUANTITY('WHEN-VALIDATE-ITEM');

如果要汇总的栏位来自多个栏位的运算,需要在每个栏位的WHEN-VALIDATE-ITEM时写运算重新计算值赋给要汇总的栏位。

6.:HEADERS的POST-QUERY Trigger中从数据库中抓取初始的汇总值,例:

Declare
V_SUM NUMBER;
BEGIN
SELECT NVL(SUM(QUANTITY), 0)
INTO V_SUM
FROM LINES
WHERE HEADER_ID = :HEADERS.HEADER_ID;
:HEADERS.QTY_SUM := V_SUM;
:HEADERS.QTY_SUM_RTOT_DB := V_SUM;----------------------注①
END;

7.:LINES的如下TRIGGER中写相应代码:
--KEY-DELREC
RUNNING_TOTAL_QUANTITY('KEY-DELREC');
DELETE_RECORD;

RUNNING_TOTAL_QUANTITY('UNDELETE');----------------------注③

--KEY-DUPREC
RUNNING_TOTAL_QUANTITY('KEY-DUPREC');
DUPLICATE_RECORD;

--KEY-CLRREC
RUNNING_TOTAL_QUANTITY('KEY-CLRREC');
CLEAR_RECORD;--(网上例子为:APP_FOLDER.EVENT('KEY-CLRREC');)

--POST-QUERY
RUNNING_TOTAL_QUANTITY( 'POST-QUERY' );

--WHEN-CLEAR-BLOCK
RUNNING_TOTAL_QUANTITY( 'WHEN-CLEAR-BLOCK' );----------------------注②

注:网上例子中还有post_insert,post_update,pre_record中写,我目前没写,测试OK,不知道会有什么漏洞,暂时没测出来。

另外上面的链接中,作者的例子会有问题,像链接文章评论所说,作者需增加 注① 的代码 ,即 WHEN-CLEAR-BLOCK的代码需和注①同时存在(查询发现EBS中PO的画面也是这么做的)。

最初我没有写 注② 和 注① 的代码 ,后经测试, 缺少这两部分会出现问题 ,还是举个例子说吧:

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

例: Line项只有一条记录,值为100,

1)正常查询出来记录后,汇总栏显示100;

2)修改记录值为99,汇总栏变为99;

3)按F11,会提示"是否保存记录",选择"否";

--此时汇总栏值为99(正常情况下此时汇总栏显示100)。

4)执行Ctrl+F11;

--此时汇总栏值依然为99(正常情况下此时汇总栏显示100,(且很大问题是此时Line值为100,汇总为99))。

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

所以:注② + 注①一定要写。

注③: Block的Delete Allowed设置为No,由于种种原因,Delete按钮是亮的。这种情况下,点击 Delete按钮 的时候会提示

FRM-41049:You cannot delete this record.但是汇总量会被减掉,一直点下去,会一直减掉..直至负NNNN...

所以加上 注③,以避免这种情况时汇总量的错误。

至于其它在 APP_CALCULATE.RUNNING_TOTAL 中涉及到的 Trigger中是否要写以及如何写,还未测试,目前为止,应用正常。

(有一点问题,即"新增一条记录,保存,然后点击clear-record按钮",数量会减掉,还未解决,其余Trigger应该也需要加上,但是有几个Trigger好像在Block下面没有,但又有其它Trigger调用在它们中产生的全局变量,暂时未过多测试。。Busy。。)


另外,如果汇总结果要拿来与其它值作比较,比如超过了某个值则raise error,则要注意running_total和比较大小两者的先后顺序。

如在when-validate-item时比较,则在此trigger中先running_total,后比较,否则...

--------------------------------------------------------------------------------------------------------------------------------------------------

附APP_CALCULATE.RUNNING_TOTAL原代码:

PACKAGE BODY app_calculate IS

PROCEDURE running_total(event VARCHAR2,
source_field VARCHAR2,
total_field VARCHAR2) IS
Last_Val_Field VARCHAR2(61) := Source_Field || '_RTOT_OLD';
DB_Source_Field VARCHAR2(61) := Source_Field || '_RTOT_DB';
DB_Total_Field VARCHAR2(61) := Total_Field || '_RTOT_DB';
Last_Value NUMBER;
Source_Value NUMBER;
DB_Source_Value NUMBER;
Total_Value NUMBER := NVL(name_in(Total_Field), 0);
DB_Total_Value NUMBER := NVL(name_in(DB_Total_Field), 0);
New_Total NUMBER;
Form_Id FORMMODULE;
BEGIN
COPY('Entering app_calculate.running_total. Event is ' || event || '.',
'global.frd_debug');
IF (event <> 'WHEN-CLEAR-BLOCK') THEN
Last_Value := NVL(name_in(Last_Val_Field), 0);
Source_Value := NVL(name_in(Source_Field), 0);
DB_Source_Value := NVL(name_in(DB_Source_Field), 0);
END IF;

IF (event = 'POST-QUERY') THEN
copy(to_char(Source_Value), DB_Source_Field);
copy(to_char(Source_Value), Last_Val_Field);

ELSIF (event = 'WHEN-CLEAR-BLOCK') THEN
IF (Total_Value <> DB_Total_Value) THEN
copy(to_char(DB_Total_Value), Total_Field);
END IF;

ELSIF (event = 'WHEN-VALIDATE-ITEM') THEN
IF (Source_Value <> Last_Value) THEN
New_Total := Total_Value - Last_Value + Source_Value;
copy(to_char(New_Total), Total_Field);
copy(to_char(Source_Value), Last_Val_Field);
END IF;

ELSIF (event = 'KEY-DELREC') THEN
IF (Last_Value <> 0) THEN
New_Total := Total_Value - Last_Value;
copy(to_char(New_Total), Total_Field);
END IF;
copy(to_char(Source_Value), Last_Val_Field);

ELSIF (event IN ('POST-INSERT', 'POST-UPDATE')) THEN
IF (Source_Value <> DB_Source_Value) THEN
copy(to_char(DB_Source_Value), Last_Val_Field);
copy(to_char(Source_Value), DB_Source_Field);
END IF;

ELSIF (event = 'PRE-RECORD') THEN
IF (Source_Value <> Last_Value) THEN
Form_Id := Find_Form(Get_Application_Property(Current_Form_Name));
IF (Name_In('GLOBAL.RTOT_' ||
substr(source_field,
1,
least(instr(source_field, '.') - 1, 15)) ||
to_char(Form_id.id)) = 'N') THEN
copy(to_char(Last_Value), DB_Source_Field);
END IF;
copy(to_char(Source_Value), Last_Val_Field);
END IF;

ELSIF (event = 'PRE-COMMIT') THEN
Form_Id := Find_Form(Get_Application_Property(Current_Form_Name));
copy('N',
'GLOBAL.RTOT_' ||
substr(source_field, 1, least(instr(source_field, '.') - 1, 15)) ||
to_char(Form_id.id));

ELSIF (event = 'POST-FORMS-COMMIT') THEN
Form_Id := Find_Form(Get_Application_Property(Current_Form_Name));
copy('Y',
'GLOBAL.RTOT_' ||
substr(source_field, 1, least(instr(source_field, '.') - 1, 15)) ||
to_char(Form_id.id));
IF (Total_Value <> DB_Total_Value) THEN
copy(to_char(Total_Value), DB_Total_Field);
END IF;

ELSIF (event = 'UNDELETE') THEN
New_Total := Total_Value + Source_Value;
copy(to_char(New_Total), Total_Field);
copy(to_char(Source_Value), Last_Val_Field);

ELSIF (event = 'KEY-DUPREC') THEN
New_Total := Total_Value + Source_Value;
copy(to_char(New_Total), Total_Field);
copy(to_char(Source_Value), Last_Val_Field);
copy(NULL, DB_Source_Field);

ELSIF (event = 'KEY-CLRREC') THEN
IF (Last_Value <> DB_Source_Value) THEN
New_Total := Total_Value - Last_Value + DB_Source_Value;
copy(to_char(New_Total), Total_Field);
END IF;
ELSE
message('Invalid event ' || event ||
' in app_calulate.running_total');
END IF;
COPY('Completed app_calculate.running_total. Event is ' || event || '.',
'global.frd_debug');

END running_total;

END app_calculate;


代码 例子 情况 问题 测试 按钮 数据 数据库 结果 两个 作者 数量 时候 链接 处理 提示 查询 运算 复杂 很大 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司 云之行互联网科技 朗新科技与工业互联网 互联网金融与金融科技 互联网科技小额贷款 互联网科技的未来发展 济南和联互联网科技有限公司 博兴的互联网电子科技公司 以后互联网后是啥科技 重庆威客帮互联网科技 互联网和黑科技的看法 彤创互联网科技有限公司 昊天互联网科技有限公司 移动互联网科技公司 乌鲁木齐新华智原互联网科技学校 图游互联网科技 互联网科技的前景 互联网科技博主张洲 杭州科技互联网公司有哪些 互联网科技创业计划的风险分析 哈尔滨大商圈互联网科技有限公司 互联网科技工作委员会主任 科技创新与互联网经济 互联网金融 科技金融 盛创互联网科技有限公司 山东吉时兔互联网科技有限公司 昊天互联网科技有限公司 青岛科技大学互联网大赛研究生 晓花互联网科技有限公司网址 数字互联网科技有限公司
0