技术开发 频道

ORACLEERP开发基础之EBS开发基础

  【IT168 技术文档】
       ORACLEERP开发基础之前言

  http://tech.it168.com/a2009/0427/274/000000274048.shtml

  ORACLE ERP开发之OracleForms基础(一)Forms设置部分

  http://tech.it168.com/a2009/0428/274/000000274178.shtml

  ORACLEERP开发基础之OracleForms基础(二)FORMS代码部份

  http://tech.it168.com/a2009/0428/274/000000274236.shtml

  ORACLE ERP开发基础之Oracle Report基础

  http://tech.it168.com/a2009/0429/274/000000274343.shtml

     ORACLEERP开发基础之Oracle数据库基础
      http://tech.it168.com/a2009/0504/274/000000274773.shtml
  
       开发工具安装

  Oracle EBS11i 开发工具是developer6i的东西,非常古老。因为是转手过来的机器,开发工具都是安装好了,

  所以也没去在意这工具的安装。今天系统重装了,才知道这工具安装起来也是特烦人的。

  先安装FORMS6i与REPORT6i,安装完后一定要打补丁。否则会出现一大堆莫名的错误。接着安装discoverer。

  安装discoverer时先将注册表备份出来,因为discoverer不能和Forms安装在同一目录。然后再安装 discoverer的补

  丁,接着再将注册表恢复回来。

  大致这样可以了。注意顺序一定要不能错了,否则又会出现一堆无聊的错误。唉!developer6i是98年的工

  具。盼着EBS R12应该是用DEVELOPER10g吧。

  EBS二次开发包注册

  2.1 从 Server 中下载 ERP Library (.pll), 存放于本机Server Path : /u01/au/11.5.0/resource

  Form文件与Library文件要存放在固定目录

  例如: Form存放在 d:\ErpForm\Form

  Library 存放在d:\ErpForm\Library;

  2.2 在 Regedit > HKEY_LOCAL_MACHINE > SOFTWARE > ORACLE > FORMS60_PATH

  加入client 端存放 Form 及 Library的路径(如图)

  例如:d:\ErpForm\Library;d:\ErpForm\Form(建议要加在最前面)

  利用TEMPLATE.fmb 模板来开发Form

  Oracle 已经为我们提供了一个Form 的开发模板,(/data/deve/devappl/au/11.5.0/forms/ZHS/TEMPLATE.fmb)

  我们的开发实际要基于这个模板,这个模板里面已经存在了我们将会用到的Oracle 标准的对象,我们需要做的,

  就是这这个模板的基础上面,添加我们自己的对象。这也是人家说二次开发没啥技术含量的重大原因。但如果

  真让你出写那么PL 包,估计也没几人能写好。人有时就是这样,让你站在巨人的肩膀,还在抱怨这抱怨那的。

  我也是这类人啦。出出气呀。^_^!

  1、更改template.fmb 文件名,同时删除一些无用的样本对象。
 


 

  2、增加数据块

  一路照做就可以了,步骤太简单就不用讲了吧。完成后,选择“仅创建数据块”。

  3、增加一个画布

  选择工具菜单上面的布局向导来做。

  注意:选择画布时,选择新画布。如上图。

  显示记录数一般为10就可以了。如上图。

  注:将画布名称改成与数据块的名称一致

  4、增加一个窗口

  注:窗口尽量保持与画面一致,同时选择相应的主画布。对应的画布那边也要选择主窗口

  5、选择对象的子类信息

  所有的对象都应选择相对的子类信息,这边仅以BLOCK为例。

  6、调整布局 不需要显示到画布的ITEM,可以将ITEM的画布属性设成空

  7、修改触发器(这一步很关键!)

  8、选择第一导航块

  9、上传及编译FORMS

  9.1先将FORMS上传至/data/deve/devappl/au/11.5.0/forms/ZHS/

  9.2telnet至server,进入/data/deve/devappl/au/11.5.0/forms/ZHS/目录

  目录:cd /data/deve/devappl/au/11.5.0/forms/ZHS/ 编译:f60gen FRMSTONE.fmb apps/apps 复制:cp FRMSTONE.fmx /data/deve/deveappl/hek/11.5.0/forms/ZHS/ 注:一定要进入FORM的目录,再进行编译。否则编译也可以通过,但会出现奇怪的问题。这个问题折腾了我二天时间,才发现是ORACLE的BUG。 好了,一个最基本的EBS FORM就开发完成了。

  注册表单FORM

  1.定义表单

  操作路径:应用开发员=>应用产品=>表单

  填写说明如下:

  表单:FORMS文件名

  应用:HEK 惠尔康客户化应用

  用户表单名:这个参数与“功能”中的表单名是相关联的。

  2.定义功能 操作路径:应用开发员=>应用产品=>功能

  2.1

  2.2

  2.3

  3.定义菜单

  操作路径:应用开发员=>应用产品=>菜单

  注:“子菜单”是指菜单可以将另一个菜单的功能全部包含进来。也就是父菜单的关系。

  5. 完成设置,效果如下:

  注册请求

  1.定义可执行

  路径:系统管理员->并发->方案->可执行

  注意:定义成请求的过程或函数,必须加入(Errbuf Out Varchar2,Retcode Out Number)两个形参。

  2.定义并发程序

  路径:系统管理员->并发->方案->可执行

  注意:并发程序界面的可执行组中的“名称”,与上面的可执行并发程序界面的“简称”是一致的。

  注意:如果要传入参数到PL/SQL包中,点击《参数》按钮进行设置。

  也可以为参数赋给默认值,例:默认取得用户ID

  如果要限定参数的取数范围,则要定义值集(如何定义?请参考后面的定义值集)。

  3.定义请求组 路径:系统管理员->安全性->责任->请求

  4.将请求组置于职责下

  系统管理员->安全性->责任->定义
 

  注册职责

  1.新建菜单 操作路径:应用开发员=>应用产品=>应用菜单

  2.新建一个职责

  操作路径:系统管理员=>安全性=>责任=>定义

  将职责分配给用户

  操作路径:系统管理员=>安全性=>用户=>定义

  3.转到EBS主页,多显示一个职责。

  注册值集

  1.定义集 操作路径:总帐=>设置=>财务系统=>验证=>集

  1.1如果值的来源于数据表,则值的验证类型选择“表”,然后点击“编辑信息”。

  注:如果要实现请求参数的值集来源,作前后过滤条件的话。其语法:

  where head.customer_number = :$FLEX$.HEK_OM_KHJGB_ACCT_CUST

  and head.created_by = :$FLEX$.HEK_OM_FHD_CREATE_BY

  and TO_CHAR(head.ordered_date,'YYYYMMDD') = :$FLEX$.HEK_DAY_TIME_ID ORDER BY HEAD.ORDER_NUMBER

  :$FLEX$.为参数界面的名称

  HEK_OM_KHJGB_ACCT_CUST为某个参数的值集名称。

  1.2实现的效果如下:

  1.3定义多列值集

  1.4实现效果

  1.5从属

  2.定义值

  2.1如果值的来源固定的某些值,那么可以直接定义值。将值的验证类型选择=>独立

  2.2定义集所对应的值

  操作路径:操作路径:总帐=>设置=>财务系统=>验证=>值

  通过应用开发员取得系统管理员责任

  一般公司都有区分DBA与DEVELOPER的,业务机上一般是APPS用户由DBA掌握,诸如用户管理也是DBA来负责的。developer是不知道 没有APPS密码,也没有‖SYSTEM ADMINISTTRATOR―职责的。也就是说DEVELOPER只有‖Application Developer―这个职责。同理,应用开发员是没有权限给终端用户加权限的。 但我今天测试了一下,developer虽然没直接加职责的权限,但developer有‖Application Developer―职责,这个职责下面有注册菜单的权限,完全可以通过注册菜单将SYSTEM ADMINISTROR加进来。如图:

  查询视图时没有显示数据

  在EBS以外的地方(含report),如果确认SQL语句没有问题,这主要是因为视图是OU屏蔽的,因此需要初始化身份。例如:PO_HEADERS。有两种方法,方法一适用于知道相应的组织代码,方法二就比较通用了。

  方法一:

  BEGIN

  DBMS_APPLICATION_INFO.set_client_info(122); --122代表具体的组织代码,不同公司,代码是不同。

  END;

  方法二:

  BEGIN

  APPS.FND_GLOBAL.apps_initialize

  ( user_id =>APPS.FND_GLOBAL.user_id, resp_id =>APPS.FND_GLOBAL.resp_id, resp_appl_id =>APPS.FND_GLOBAL.resp_appl_id );

  END;

  注册报表(report)

  路径:系统管理员->并发->方案->可执行

  注册报表与注册请求的步骤是差不多的。

  定义并发

  路径:系统管理员->并发->方案->定义

  定义报表参数

  点击上图的参数按钮。

  注:这边与注册请求不一样的就是,要填写变量栏(变量名称就是REPORT中的变量名称)

  定义请求组

  操作路径:系统管理员->安全性->责任->请求

  将请求组置于职责下

  系统管理员->安全性->责任->定义

  OK,完成了报表的注册。

  请求的输出及日志

  1、Effect:

  Oracle EBS会在EBS的安装目录,保存查看输出及日志之文件。查看具体目录:

  select t.logfile_name,t.outfile_name from fnd_concurrent_requests t

  where t.request_id = _request_id

  2、当我们自行定义了一个并发请求时,也经常需要使用上面的方式进行一些调试。

  请求的输出:apps.Fnd_File.Put_line (apps.FND_FILE.OUTPUT, '请求的输出');

  请求的日志:apps.Fnd_File.Put_line (apps.FND_FILE.LOG, '请求的日志');

  对于报表,一般情况是把报表的内容输出到OUTPUT,把报表中间的debug逻辑输出到日志中。

  对于请求包,一般情况是输出到日志中。OUTPUT就不用管了。

  实现手动提交请求

  在Form里面,我们可以用

  APPS.FND_REQUEST.SUBMIT_REQUEST

  提交一个Request到Oracle Request Manager。如果提交成功,该函数返回Request ID,否则,返回0。

  1、初始化

  在提交一个Request之前,我们会调用Oracle Standard的Procedure对这个Request做一些基本的参数的初始化。

  APPS.FND_GLOBAL.apps_initialize

  ( user_id =>APPS.FND_GLOBAL.user_id, resp_id =>APPS.FND_GLOBAL.resp_id, resp_appl_id =>APPS.FND_GLOBAL.resp_appl_id );

  注:这个初始化不是必须的,之所以要初始化,是因为视图是OU屏蔽的。 上述语句等同于dbms_application_info.set_client_info;

  2、函数介绍

  2.1 函数APPS.FND_REQUEST.SUBMIT_REQUEST有105个参数:

  APPS.FND_REQUEST.SUBMIT_REQUEST

  ( APPLICATION IN VARCHAR2 DEFAULT NULL,

  PROGRAM IN VARCHAR2 DEFAULT NULL,

  DESCRIPTION IN VARCHAR2 DEFAULT NULL,

  START_TIME IN VARCHAR2 DEFAULT NULL,

  SUB_REQUEST IN BOOLEAN DEFAULT FALSE,

  chr(0),'','','','','','','','','','','','','','','','','','','', '','','','','','','','','','', '','','','','','','','','','', '','','','','','','','','','', '','','','','','','','','','', '','','','','','','','','','', '','','','','','','','','','', '','','','','','','','','','', '','','','','','','','','','' )

  RETURN NUMBER;

  2.2 参数详解

  2.2.1 APPLICATION(必需参数)

  应用程序的名称缩写。一般我们可能会用到下面的几个:

  Oracle Assets „„> OFA

  Oracle General Ledger „„> SQLGL

  Oracle Inventory „„>INV

  Oracle Order Management „„>ONT

  Oracle Payables „„SQLAP

  Oracle Pricing „„QP

  Oracle Purchasing „„PO

  Oracle Receivables „„AR

  操作路径:系统管理员=>应用=>注册

  2.2.2 PROGRAM(必需参数)

  要提交到Oracle Request Manager的并发程序之简称

  操作路径:应用开发员=>并发=>程序

  2.2.3 第三、第四个参数

  第三、第四个参数默认为空

  2.2.4 第五个参数

  第五个参数默认为false

  2.2.5 第六至第十零五个参数

  第六至第十零五个参数为要传入到请求中的自定义参数值。如果无须这么多参数时,以chr(0)作为参数结束的标记。Chr(0)后面剩余的参数为 ‘‘。

  手动提交请求示例

  declare

  v_order_number number;

  v_req_id number;

  begin

  v_order_number := :HEK_ODS_TH_FEE_M_V.OE_HEAD_NUMBER;

  if :HEK_ODS_TH_FEE_M_V.OE_HEAD_NUMBER is null then FND_MESSAGE.DEBUG('请选择配送单后再打印!');

  RAISE FORM_TRIGGER_FAILURE;

  end if;

  v_req_id := fnd_request.submit_request('HEK',

  'HEK_退货单',

  '', '',

  FALSE, v_order_number,--v_batch_no, null,--v_batch_no, null,--v_cust_num, null,--v_driver_num, null,--v_trans_num, null,--v_vendor_num, null, null,null, chr(0), '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '','');

  if (v_req_id = 0) then FND_MESSAGE.RETRIEVE;

  FND_MESSAGE.ERROR;

  else

  update HEK_ODS_TH_FEE_M set print_mark='Y' where OE_HEAD_NUMBER = (v_order_number);

  commit_form;

  fnd_message.debug('您的请求已经提交,请求号为:' || to_char(v_req_id) || ',请通过查看->请求来查看输出结果。');

  end if;

  end;

  客制化菜单

  Effect:

  Usage:调用 app_special.instantiate包

  Examples:

  1、增加一个自定义Form Level的触发器(SPECIAL11)

  2、增加测试代码如下:

  ――――――――――――――――――――――――――――――――――――――――――――――

  declare

  v_invoice_num varchar2(50);

  begin

  v_invoice_num := '菜单栏客制化100';

  fnd_message.debug(v_invoice_num);

  end;

  ―――――――――――――――――――――――――――――――――――――――――――――――

  3、在Form WHEN-NEW-FORM-INSTANCEFJ 进行调用:

  APP_SPECIAL.INSTANTIATE('SPECIAL11','测试菜单2', '', TRUE, 'LINE');

  ―――――――――――――――――――――――――――――――――――――――――――――――

  4、一些特殊说明:

  上面自定义FORMS级触发器,名字必须定义为“SPECIAL+数字‖,否则会报错。并且数字的大小决定了菜单出现的先后顺序。数字还有更大作用就是决定了,自定义菜单选项放在哪个主菜单下。

  SPECIAL1—SPECIAL15在“工具”主菜单下。

  SPECIAL16—SPECIAL30在“报表”主菜单下。

  SPECIAL31—SPECIAL45在“活动”主菜单下。

  SPECIAL46以上就直接报错了。^_^

  如下图

  5、 控制自定义菜单的是否激活可用。

  使用app_special.enable函数可以控制菜单是否可以使用。

  例如:基于不同的数据块,实现菜单的不可用。在block的‖when-new-block-instance‖中加入

  效果:

  app_special.enable('SPECIAL1',property_off);

  效果

  6、 在自定义的菜单上使用checkbox按钮。

  ①增加一个自定义Form Level的触发器(SPECIAL1_CHECKBOX),代码如下:

  if app_special.get_checkbox('SPECIAL1_CHECKBOX')='TRUE' then

  fnd_message.debug('Special 1 is True!');

  else

  fnd_message.debug('Special 1 is False!');

  end if;

  注:使用app_special.get_checkbox来获取checkbox的状态值。

  ②在Form的WHEN-NEW-FORM-INSTANCE触发器中初始化菜单。

  app_special.instantiate('SPECIAL1_CHECKBOX','Spe&cial 1 Box w Line', '',TRUE,'LINE');

  app_special.set_checkbox('SPECIAL1_CHECKBOX','TRUE');

  注:app_special.set_checkbox是对checkbox进行赋值操作。

  ③效果如下:

  客制化右键菜单

  1、 首先如果是要为某个ITEM,另外开发一个右键菜单。这个需要直接按照FORM的开发教程,自定义一个POPUP菜单就可以了。但本文讲的在EBS所有的快捷菜单上,额外增加所需的菜单按钮。也就是要图上所示的快捷菜单上增加菜单按钮。

  2、 在FROM-LEVEL增加自定义触发器(名字规则为:POPUP+N)

  3、 ITEM的“PRE-POPUP-MENU”触发器上初始化菜单。

  APP_POPUP.INSTANTIATE('POPUP1','First Entry');

  APP_POPUP.INSTANTIATE('POPUP10','SECONED Entry',TRUE,'LINE');

  APP_POPUP.INSTANTIATE('POPUP3','THREE Entry',FALSE,NULL);

  4、 如果是整个BLOCK的ITEM都需要客制化快捷菜单,可以在BLOCK的“PRE-POPUP-MENU”定义。

  APP_POPUP.INSTANTIATE('POPUP1','global');

  调用EBS日期控件

  1、 首先将ITEM的LOV属性设置为“ENABLE_LIST_LAMP”、列表验证属性设置为“否”

  2、在ITEM的“KEY-LISTVAL”解发器下加入对下代码:

  BEGIN

  calendar.show();

  END;

  3、注意:ITEM对应数据库类型必须是DATE类型,否则会报frm-40700错误。效果如下:

  查询数据时限定语言环境

  EBS是个多语言的业务系统,界面上只查询到一条记录,实际上后台数据表是多条记录的。如:值集表。

  select * from apps.FND_FLEX_VALUES_TL t, apps.FND_FLEX_VALUES B

  where B.FLEX_VALUE_ID = T.FLEX_VALUE_ID

  and t.language = userenv('LANG')

  实现历史记录查询

  1.要实现的效果

  2.在定义数据表时,必须加入以下五个字段:

  即:CREATED_BY NUMBER、CREATION_DATE DATE、LAST_UPDATED_BY NUMBER、LAST_UPDATE_DATE DATE、LAST_UPDATE_LOGIN NUMBER 网上有些文章说还必须定义主键、序列。但如果仅实现此功能是不需要的。当然从数据库设计方面来说,这些定义也是必须的。

  3、在数据块的PRE-INSERT、PRE-UPDATE触发器中加入代码 FND_STANDARD.SET_WHO;

  实现文件夹功能

  1、在客制的Form里面实现Oracle Folder的功能,最终效果如下:

  2、使用TEMPLATE.fmb创建一个Form(名称:FRMSTONE)。

  2.1添加Form Objects 包括一个Window,MY_FOLDER

  一个Canvas, MY_FOLDER 一个Block,MY_FOLDER(可以使用向导创建),并修改其属性。如下图:

  注:使用文件夹的数据块,其名称总长不能超过22字节!

  2.2修改Trigger和ProgramUnits

  Form Level Trigger: PRE-FORM:

  app_window.set_window_position('MYFOLDER', 'FIRST_WINDOW');

  Program Units:APP_CUSTOM:

  if (wnd = 'MYFOLDER') then app_window.close_first_window;

  2.3修改FORM属性设置

  注:须要说明的是:设成第一个导航数据块的blockname必须至少一个item处于canvas中,否则会报FRM-40106的错误。

  2.4其他的具体步骤同一般的FORM开发一样,就不多说了。

  3、添加Folder相关的Objects

  3.1文件夹相关的Window、Canvas、Block、Item…等都包含在Oracle Standard Form APPSTAND.FMB。

  3.2在同一窗口打开标准的Form和我们自己客制的Form,并且选择APPSTAND.FMB 的Object Groups STANDARD_FOLDER然后用鼠标拖动至我们自己的Form的Object Groups。

  3.3此时会弹出对话框:

  选择子类,你会发现Form Builder都会在你的Form里面自动添加很多对象。做完这一步后,请不要关闭APPSTAND.FMB。

  4、增加Attached Libraries

  做完上面的步骤后,检查一下Attached libraries里面有没有APPFLDR。如果没有,我们需要手工添加。

  5、增加Stacked Canvas FOLDER_STACK 这一步是必须的,而且你期望实现Folder拖动功能的那些Item都是放在这个Canvas里面,这个Stacked Canvas又是放在前面我们建立的Canvas:MY_FOLDER上面的。

  5.1增加Stacked Canvas 双击打开Canvas MY_FOLDER,在左侧工具条里面选择Stacked Canvas,然后在Canvas MY_FOLDER里面拖动即可。

  5.2设置Stacked Canvas属性

  6、更改数据块MY_FOLDER中的Item属性

  7、创建控制块MY_FOLDER_PROMPT

  7.1设置块的属性 子类信息:block 数据库数据块:否

  7.2增加ITEM 注:增加Item,名称必须和Block MY_FOLDER中的Item保持一致。 另外,数据块中有些item(如id)不要显示在canvas上的,那么此类item也无须在MY_FOLDER_PROMPT创建相应的item.

  7.2设置其初始值,也就是显示的标签名及子类信息

  7.3增加其他相关Item 我们还需要增加其他的一些Item,都是和Folder的功能有关的。

  8、增加相应的trigger

  9、其他注意事项

  9.1错误:在编译带有文件夹的FORM时,经常会出现如下提示。

  FRM-30085: Unable to adjust form for output

  这是因为ITEM超出的了画布的高度或是宽度造成的。如图:

  可以通过调整ITEM的X坐标或Y坐标来解决此错误。

  9.2错误:无法实现拖动。

  解决:数据块的item与folder的item与调整一定的距离。

  实现手电筒查找的功能

  首先,先按TEMPLATE将其他功能先实现,然后再来实现查找的功能。手电筒查找的Effect有两二种,①LOV形式,②window形式。

  1、LOV查找模式:一般适用于查询结果只返回单条条件的查询(如主从数据块的界面)。

  ①创建一个parameter参数:TEST_P

  ②创建一个基于主键查询LOV-TEST_L,并将主键字段映射给Parameter参数TEST_P。

  ③在数据块中创建PRE-QUERY触发器。

  IF :parameter.G_query_find = 'TRUE' THEN :BLOCKNAME.HEADER_ID := :parameter.TEST_P; :parameter.G_query_find := 'FALSE';

  end if;

  ④在数据块中再创建QUERY_FIND触发器。

  begin

  app_find.query_find('TEST_L'); --调用LOV

  end;

  ⑤完成效果如下:

  2、WINDOW查找模式:一般适用多条件查询,可以返回多条查询记录。

  ①打开在标准FORM---APPSTAND.fmb。将对象组中的QUERY_FIND拖至待开发的FORM中。

  ②重命名第一个数据块、画布、窗口(QUERY_***都是刚才自动创建的)。USER GUID说可以重命名,但我没有重命名成功。也懒得去折腾一个命名的问题。^_^ ③打开QUERY_FIND画布,改写“新建”、“查找”两个按钮WHEN-BUTTON-PRESS之中的代码。

  NEW按钮代码:

  --app_find.new('Your blockname here'); app_find.new('HEK_SALE_CUST_MANUAL');

  FIND按钮代码:

  :parameter.G_query_find := 'TRUE'; --app_find.find('your blockname here'); app_find.find('HEK_SALE_CUST_MANUAL'); :parameter.G_query_find := 'FALSE';

  ④设置QUERY_FIND数据块的“前一导航数据块”,也就是要实现询查功能的数据块。

  ⑤修改QUERY_FIND数据块KEY-NXTBLK触发器代码

  :parameter.G_query_find := 'TRUE'; --app_find.find('your blockname here'); app_find.find('HEK_SALE_CUST_MANUAL'); :parameter.G_query_find := 'FALSE';

  ⑦修改QUERY_FIND窗口的标题及尺寸,并在QUERY_FIND画布上创建要查找的条件ITEM。 ⑧在要实现查询的数据块(如:HEK_SALE_CUST_MANUAL),创建PRE-QUERY触发器。

  if :parameter.g_query_find = 'TRUE' then

  app_find.query_range(name_in('query_find.CUSTOMER_NUMBER'),name_in('query_find.CUSTOMER_NUMBER'),'HEK_SALE_CUST_MANUAL.CUST_CODE');

  app_find.query_range(:query_find.CUST_DATE,:query_find.CUST_DATE,'HEK_SALE_CUST_MANUAL.TIME_ID'); :parameter.G_query_find := 'FALSE';

  end if;

  注:app_find.query_range参数前两个是QUERY_FIND中的ITEM,后一个是查询块中的ITEM。

  ⑨在要实现查询的数据块(如:HEK_SALE_CUST_MANUAL),再创建QUERY_FIND触发器。

  --APP_FIND.QUERY_FIND('','',''); app_find.query_find('HEK_SALE_DEPT_MANUAL','QUERY_FIND','QUERY_FIND');

  ⑩完成效果如下:

  记录指示器切换标签页

  Effect:

  1、 在该数据块中手工增加一个ITEM

  设置ITEM的属性:子类信息:设成DRILLDOWN_RECORD_INDICATOR,数据库项:否.

  2.在新增的ITEM的WHEN-MOUSE-CLICK触发器加入

  declare

  v_order number;

  begin

  v_order := : block_name1.item; --block_name表示要切换tab的数据块

  if v_order is not null then

  go_block(' block_name1');

  set_block_property('block_name1 ',DEFAULT_WHERE,'ORDER_NUMBER='||v_order);

  execute_query;

  end if;

  end;

  3.这样就可以实现类似VB中的TAB切换了。由于ORACLE FORM没有专门的TAB函数,只能如此曲折实现。

  EBS的条件查询方法

  1、使用app_find.find

  IF (NAME_IN('PO_HEADERS.PO_HEADER_ID') IS NOT NULL) THEN

  :parameter.G_query_find := 'TRUE';

  app_find.find('CUX_PO_HEADERS_ADD_MESSAGE');

  go_block('CUX_PO_HEADERS_ADD_MESSAGE');

  :parameter.G_query_find := 'FALSE';

  ELSE

  FND_MESSAGE.DEBUG('请先保存订单头');

  END IF;

  在CUX_PO_HEADERS_ADD_MESSAGE的PRE-BLOCK中处理

  copy(name_in('PO_HEADERS.PO_HEADER_ID'),'CUX_PO_HEADERS_ADD_MESSAGE.PO_HEADER_ID');

  2、使用Default_where属性处理

  declare

  lv_default varchar2(2000);

  begin

  lv_default:='.....';

  go_block('CUX_PO_HEADERS_ADD_MESSAGE');

  set_block_property('CUX_PO_HEADERS_ADD_MESSAGE',DEFAULT_WHERE,‘PO_HEADER_ID=‘||lv_default);

  execute_query;

  end;

  3、使用app_find.query_range()来处理 注:app_find.query_range()必须有三个参数,也只能有三个参数

  begin

  app_find.query_range(:find_date_from, :find_date_to, 'CUX_PO_HEADERS_ADD_MESSAGE.REATE_DATE'); :parameter.Q_query_find:='false';

  end;

  4、查询综合运用举例

  前提准备工作,数据块:HKE_TEST 控制块:CONTROL

  4.1.在数据块HKE_TEST的PRE-QUERY触发器设定查询条件

  if :parameter.g_query_find = 'TRUE' then

  app_find.query_range(:CONTROL.CUST_F, :CONTROL.CUST_F ,'HKE_TEST.CUSTOMER_NUMBER'); :parameter.g_query_find := 'FALSE';

  end if;

  4.2在查询按钮的WHEN-BUTTON-PRESSED

  :parameter.G_query_find := 'TRUE';

  app_find.find('HEK_TEST');

  :parameter.G_query_find := 'FALSE';

  自定义代码

  例:实现某个项为必填项(当然自定义代码的功能还有很多)。

  菜单:诊断=>自定义代码=>个性化

  选择相应的触发器。如果是基于block的触发器,则要选择触发器对象(是哪一个块?)。

  选择相应的项为必填。注:项的名称可通“检查”来查看。

  作用于项的内容是什么,本例为必填。

  保存完后,就可以实现“销售人员这一项为必填了”。

  Fnd_Profile

  begin

  fnd_message.debug('user_id= ' || fnd_profile.value('user_id')); --取当前登录EBS用户ID

  fnd_message.debug('user_name= '||fnd_profile.value('USERNAME')); --取当前登录EBS用户名

  fnd_message.debug('FND_Global.User_Name='|| FND_Global.User_Name); --取当前登录EBS用户名 fnd_message.set_string('GL_SET_OF_BKS_ID='||fnd_profile.value('GL_SET_OF_BKS_ID'));

  fnd_message.show; --取当前帐套

  end;

  弹性域

  弹性域分成键弹性域、说明性弹性域。这两种弹性域用途是不一样的。 关键性弹性域:在使用KEY弹性域的基表中,只保存ID。但可以通ID查询到相应的SEGMENT。在表结构中表现为***_ID、SEGMENT1等。 说明性弹性域:针对特定用户扩展输入特定信息的字段。在表结构中表现为attribute_category、attribute1字段等。

  注册关键性弹性域

  注册说明性弹性域

  1.创建数据表。

  注:使用说明性弹性域的数据表,必须含有ATTRIBUTE_CATEGORY及若干ATTRIBUTEN字段。 ATTRIBUTE_CATEGORY字段:指弹性域的CONTEXT字段。 ATTRIBUTEN字段:指实际使用的字段。

  create table HEK_DISCOUNT_POLICY_H_NEW(

  POLICY_ID NUMBER, POLICY_NO VARCHAR2(30) not null, CUSTOMER_ID NUMBER, CUSTOMER_NUMBER NUMBER , CUSTOMER_NAME VARCHAR2(100), BENIFICIARY_ID NUMBER, BENIFICIARY_NUMBER NUMBER , BENIFICIARY_NAME VARCHAR2(100), RELATION_NUMBER NUMBER , RELATION_NAME VARCHAR2(100), PAYMENT_TYPE VARCHAR2(20), POLICY_PERIOD VARCHAR2(20) not null, ATTRIBUTE_CATEGORY VARCHAR2(150), ATTRIBUTE1 VARCHAR2(150), ATTRIBUTE2 VARCHAR2(150), ATTRIBUTE3 VARCHAR2(150), CREATED_BY NUMBER, CREATION_DATTE DATE, LAST_UPDATED_BY NUMBER, LAST_UPDATE_DATE DATE, LAST_UPDATE_LOGIN NUMBER)

  2.注册弹性域表

  begin

  ad_dd.register_table('HEK','HEK_DISCOUNT_POLICY_H_NEW','T',10,10,40);

  commit;

  end;

  3.注册弹性域表的列

  begin

  ad_dd.register_column('HEK','HEK_DISCOUNT_POLICY_H_NEW','ATTRIBUTE_CATEGORY',1,'VARCHAR2',150,'N','N'); ad_dd.register_column('HEK','HEK_DISCOUNT_POLICY_H_NEW','ATTRIBUTE1',2,'VARCHAR2',150,'N','N'); ad_dd.register_column('HEK','HEK_DISCOUNT_POLICY_H_NEW','ATTRIBUTE2',3,'VARCHAR2',150,'N','N'); ad_dd.register_column('HEK','HEK_DISCOUNT_POLICY_H_NEW','ATTRIBUTE3',4,'VARCHAR2',150,'N','N');

  commit;

  end;

  4.查看是否注册成功

  select ft.table_id from FND_TABLES ft where ft.table_name='HEK_DISCOUNT_POLICY_H_NEW'

  select * from FND_COLUMNS fc where fc.table_id in (select ft.table_id from FND_TABLES ft where ft.table_name='HEK_DISCOUNT_POLICY_H_NEW')

  5.注册弹性域列 操作路径:应用开发员=>弹性域=>说明性=>注册

  点列按钮,选择注册相应的列

  6. 注册弹性域段

  点段按钮,输入提示文本

  7.启用说明性弹性域

  7.1先按将相应的FORM开发好,然后在FORM级的以下TRIGGER中加入

  PRE-QUERY: FND_FLEX.EVENT('PRE-QUERY');

  POST-QUERY: FND_FLEX.EVENT('POST-QUERY');

  PRE-INSERT: FND_FLEX.EVENT('PRE-INSERT');

  PRE-UPDATE : FND_FLEX.EVENT('PRE-UPDATE');

  WHEN-VALIDATE-ITEM: FND_FLEX.EVENT('WHEN-VALIDATE-ITEM');

  WHEN-VALIDATE-RECORD: FND_FLEX.EVENT('WHEN-VALIDATE-RECORD');

  7.2在PRE-FORM的TRIGGER中加入

  fnd_descr_flex.define ( BLOCK=>'HEK_DISCOUNT_POLICY_H_NEW',

  FIELD=>'DESC_FLEX',

  APPL_SHORT_NAME=>'HEK',

  DESC_FLEX_NAME=>'HEK返利_订金');

  说明一下相应参数:BLOCK:指启用弹性域的数据块名 FIELD:指后面新增的ITEM APPL_SHORT_NAME:指相应模块的简称(系统管理员->应用->注册) DESC_FLEX_NAME:指注册弹性域时的名称

  8.在要启用弹性域的数据块中增加一个ITEM。名称为:DESC_FLEX。

  8.1 DESC_FLEX属性设置如下:

  子类信息:TEXT_ITEM_DESC_FLEX

  数据库项:否

  画布:MAIN_C

  8.2在DESC_FLEX项的以下trigger中加入:

  WHEN-VALIDATE-ITEM :FND_FLEX.EVENT('WHEN-VALIDATE-ITEM');

  WHEN-NEW-ITEM-INSTANCE:FND_FLEX.EVENT('WHEN-NEW-ITEM-INSTANCE');

  9.完成效果:

  条件控制说明性弹性域

  说明:通过一个字段的值控制是否显示说明性弹性域。与普通的说明性弹性域类似。下面仅说明不同之处。

  1. 注册弹性域列时,定义一个参考列。

  点击参考字段按钮

  DISCOUNT_TYPE是要启用弹性域数据表中的一个字段,即通过这个字段,来控制是否显示弹性域。

  2.定义弹性域段

  新增一条上下文值记录,例:年返。即当DISCOUNT_TYPE的值为“年返”时,才显示弹性域。

  3.实现效果。

  调用会计科目弹性域

  1.首先在创建数据表时,添一个字段用来保存会计科目的ID。如:CODE_COMBINATION_ID

  2.在FORM相应的数据块增加两个ITEM,用来显示科目NUMBER与DESCRITION。

  例:GL_CODE_NUMBER、GL_CODE_DESC

  注 : ENABLE_LIST_LAMP是TEMPLATE模板自带的,无须手工去定义。 将GL_CODE_NUMBER项的LOV设成“ENABLE_LIST_LAMP”,数据库项设为“否”。 将GL_CODE_NUMBER“从列表中验证”属性设成否。

  3.在Form Level 的WHEN-NEW-FORM-INSTANCE Trigger初始化弹性域

  FND_KEY_FLEX.DEFINE(BLOCK => 'BlockName ',

  FIELD => 'GL_CODE_NUMBER',

  ID => 'CODE_COMBINATION_ID',

  DESCRIPTION => 'GL_CODE_DESC',

  APPL_SHORT_NAME => 'SQLGL',

  CODE => 'GL#', NUM => 101, --STRUCTURE Number REQUIRED => 'N' );

  说明:APPL_SHORT_NAME查找:系统管理员=>应用=>注册

  CODE查找:应用开发员=>键=>注册

  NUM查

  4.可以在GL_CODE_NUMBER项的WHEN-VALIDATE-ITEM触发器中,对所选择的科目进行核查。

  IF : BlockName.CODE_COMBINATION_ID = -1 then

  fnd_message.debug('所选科目组合无效!');

  raise form_trigger_failure;

  end if;

  5、完成效果:

  键弹性域与说明性弹性域明显的区别。就是使用键弹性域的数据表只保留了ID。以会计科目弹性域为例,数据表只保存了ID(即CODE_COMBINATION_ID,这个字段是对应会计科目的ID)。GL_CODE_NUMBER、GL_CODE_DESC都只是控制块的ITEM,通过CODE_COMBINATION_ID来查询对应的科目。

  EBS11i FormMVC模式

  一个同事在的视频会议上提到,在做EBS开发时,要用MVC模式来满足不断在变化的业务需求。很有意思的话题,值得展开讨论。JAVA设计模式的书偶看了N次,但只会在JAVA应用,但从未想过在其他的4GL编程语言实现。以下是我的理解。 首先,按JAVA的那一套,MVC是指MODEL(模型层)、VIEW(表现层)、CONTROLLER(控制层)的缩写。编写软件为什么分层,这个是软件工程的需求。也就是说分层的目的是提高软件的可维护性,避免“动一牵百”的修改软件。 其次,按照这种软件分层原理,在JAVA中比较容易实现。Struts就是这类比较典型应用。模型层可以用实体类来实现,表现层可以用JSP+STRUTS标签实现,控制层可以action类实现。那么在ORACL FORMS如何实现分层呢?以下对号入座的想法。 MODEL用数据块来实现、VIEW用FORM界面实现、控制层呢?MVC中最为关键的是CONTROLLER。因为CONTROLLER实现业务逻辑与流程流转。并且按照设计模式的要求,CONTROLLER又被分成若干小层,如DAO层、SERVICES层等等,并且带来的“面向接口编程”之方法。ORACLE FORM实现业务逻辑与界面分离是通过程序单元来实现,控制层具体表现在ORACLE FORMS当中没有,只能通过繁琐的PL/SQL语句实现。 不知道这种理解对不对。这个话题是很有意思的,大家觉得呢?欢迎讨论哦。

  EBS预警功能自定义开发

  EBS预警分为事件预警和定期预警。预警功能非常强大,本例以订单录入后,以邮件的形式通知财务主管进行“订单登记”审核。

  1、 定义预警。

  操作路径:预警系统管理器=>预警=>定义

  2、 编写SQL语句(注:SQL必须包含INTO、where rowid=:rowid)

  select ORDER_NUMBER into &order_number from OE_ORDER_HEADERS_all head WHERE rowid = :ROWID

  3、 点击上图中的“活动按钮”。

  4、 点击上图中的“活动详细资料”按钮。

  5、 定义活动集。

  6、 预警安装

  点击“预警详细资料”按钮。

  7、 完成效果如下:

  EBS自定义邮件通知

  前面已经介绍过了EBS预警的功能,事实上Oracle数据库本身就有提供UTL_SIMPLE(ORACLE10g以后变成UTL_MAIL)包来实现邮件发送的功能,利用这个包可以开发出更灵活东西来。首先要安装utlsmtp.sql、utltcp.sql这两个包。

  ①发送带有URL邮件代码

  declare

  p_sender varchar2(30) := 'chongdong_wang@hek.cn';

  p_recipient varchar2(30) := 'jian_li2@hek.cn';

  p_subject varchar2(50) := '使用PL/SQL发送邮件';

  p_body long := '这是邮件正文内容啦!我又来啦!!!进行ORACLE ERP';

  mail_conn utl_smtp.connection;

  mail_host varchar2(15) := 'mail.hek.cn';

  user_name varchar2(156) := 'chongdong_wang@hek.cn';

  user_pwd varchar2(156) := '***';

  begin --创建一个TCP MAIL连接

  mail_conn := utl_smtp.open_connection(mail_host, 25);

  --ehlo与helo的区别:是否对邮件主机进行登陆认证

  --utl_smtp.helo(main_conn,mail_host);

  utl_smtp.ehlo(mail_conn, mail_host);

  --登陆认证语句 utl_smtp.command(mail_conn, 'AUTH LOGIN');

  --对用户及密码进行加密

  utl_smtp.command(mail_conn, demo_base64.encode(utl_raw.cast_to_raw(user_name)));

  utl_smtp.command(mail_conn, demo_base64.encode(utl_raw.cast_to_raw(user_pwd)));

  --指定发件人 utl_smtp.mail(mail_conn, p_sender);

  --指定收件人 utl_smtp.rcpt(mail_conn, p_recipient);

  --开始写邮件内容 utl_smtp.open_data(mail_conn);

  --指定显示的发件人,注意这边的显示的发件人可以上面指定发件人不同

  --这实际上是SMTP协议的缺陷,也是造成垃圾邮件主要原因

  utl_smtp.write_data(mail_conn, 'From:' || p_sender || utl_tcp.CRLF); utl_smtp.write_data(mail_conn, 'To:' || p_recipient || utl_tcp.crlf);

  --邮件主题:中文必须进行编码转换,否则会乱码 utl_smtp.write_raw_data(mail_conn, utl_raw.cast_to_raw(convert('Subject:' || p_subject || utl_tcp.CRLF, 'ZHS16GBK')));

  --设置邮件内容模式为HTML,也可以直接设置文本Content-Type:text/plain

  utl_smtp.write_raw_data(mail_conn, utl_raw.cast_to_raw(convert('Content-Type:text/html;

  charset=GBK' || utl_tcp.CRLF, 'ZHS16GBK')));

  utl_smtp.write_data(mail_conn, utl_tcp.CRLF);

  --邮件正文 utl_smtp.write_raw_data(mail_conn, utl_raw.cast_to_raw(convert(p_body, 'ZHS16GBK')));

  --关闭连接 utl_smtp.close_data(mail_conn); utl_smtp.quit(mail_conn); exception when utl_smtp.transient_error or utl_smtp.permanent_error then utl_smtp.quit(mail_conn);

  raise_application_error(-20000, sqlerrm);

  when others then raise_application_error(-20001, 'The send mail was error ' || sqlerrm);

  end;

  ②发送带有附件的邮件

  declare

  p_sender varchar2(30) := 'metalink@hek.cn';

  p_recipient varchar2(30) := 'chongdong_wang@hek.cn';

  p_subject varchar2(50) := 'PL/SQL发邮件、带链接、带附件';

  p_body long := 'PL/SQL发邮件、带链接带附件

  这是邮件正文内容啦!这是带附件的啦!!

  进行ORACLE ERP';

  mail_conn utl_smtp.connection;

  mail_host varchar2(15) := 'mail.hek.cn';

  user_name varchar2(156) := 'metalink@hek.cn';

  user_pwd varchar2(156) := 'metalink'; --发附件要用到的变量

  L_FIL BFILE; L_FILE_LEN NUMBER;

  L_MODULO NUMBER; L_PIECES NUMBER;

  L_FILE_HANDLE UTL_FILE.FILE_TYPE;

  L_AMT BINARY_INTEGER:=672*3;/* ensures proper format; 2016 */

  L_FILEPOS PLS_INTEGER:=1;/* pointer for the file */

  L_CHUNKS NUMBER; L_BUF RAW(2100); L_DATA RAW(2100);

  L_MAX_LINE_WIDTH NUMBER:=54; L_LINE VARCHAR2(1000);

  L_MESG VARCHAR2(32767);

  BOUNDARY CONSTANT VARCHAR2(256) := '-----7D81B75CCC90D2974F7A1CBD';

  FIRST_BOUNDARY CONSTANT VARCHAR2(256) := '--' || BOUNDARY || utl_tcp.CRLF;

  LAST_BOUNDARY CONSTANT VARCHAR2(256) := '--' || BOUNDARY || '--' || utl_tcp.CRLF;

  --发送带有附件邮件,MIME必须设为multipart/mixed

  MULTIPART_MIME_TYPE CONSTANT VARCHAR2(256) := 'multipart/mixed; boundary="'|| BOUNDARY || '"';

  begin

  --创建一个TCP MAIL连接

  mail_conn := utl_smtp.open_connection(mail_host, 25);

  --ehlo与helo的区别:是否对邮件主机进行登陆认证 -

  -utl_smtp.helo(main_conn,mail_host);

  utl_smtp.ehlo(mail_conn, mail_host);

  --登陆认证语句 utl_smtp.command(mail_conn, 'AUTH LOGIN');

  --对用户及密码进行加密

  utl_smtp.command(mail_conn, demo_base64.encode(utl_raw.cast_to_raw(user_name)));

  utl_smtp.command(mail_conn, demo_base64.encode(utl_raw.cast_to_raw(user_pwd)));

  --指定发件人

  utl_smtp.mail(mail_conn, p_sender); --指定收件人

  utl_smtp.rcpt(mail_conn, p_recipient); --开始写邮件内容

  utl_smtp.open_data(mail_conn);

  utl_smtp.write_data(mail_conn, 'From:' || p_sender || utl_tcp.CRLF);

  utl_smtp.write_data(mail_conn, 'To:' || p_recipient || utl_tcp.crlf);

  utl_smtp.write_data(mail_conn, 'Subject: ' || p_subject || utl_tcp.crlf);

  --中文编码转换

  utl_smtp.write_raw_data(mail_conn,utl_raw.cast_to_raw(convert('Subject:' ||p_subject ||utl_tcp.CRLF,'ZHS16GBK'))); utl_smtp.write_raw_data(mail_conn,utl_raw.cast_to_raw(convert('Content-Type:'||MULTIPART_MIME_TYPE||utl_tcp.CRLF,'ZHS16GBK')));

  --utl_tcp.CRLF 数据流行尾符

  utl_smtp.write_data(mail_conn, utl_tcp.CRLF); -

  -邮件正文

  utl_smtp.write_data(mail_CONN, FIRST_BOUNDARY);

  utl_smtp.write_raw_data(mail_conn,utl_raw.cast_to_raw(convert('Content-Type:text/html;charset=GB2312' ||utl_tcp.CRLF, 'ZHS16GBK')));

  utl_smtp.write_data(mail_conn, utl_tcp.CRLF);

  utl_smtp.write_raw_data(mail_conn,utl_raw.cast_to_raw(convert(p_body, 'ZHS16GBK')));

  utl_smtp.write_data(mail_conn, utl_tcp.CRLF);

  --附件格式

  utl_smtp.write_data(mail_CONN, FIRST_BOUNDARY);

  utl_smtp.write_raw_data(mail_conn,utl_raw.cast_to_raw(convert('Content-Type:text/html;charset=GB2312' ||utl_tcp.CRLF, 'ZHS16GBK')));

  utl_smtp.WRITE_RAW_DATA(mail_conn, UTL_RAW.CAST_TO_RAW(CONVERT('Content-Disposition' || ':' ||'attachment;filename="'||'qq.xls"' || utl_tcp.CRLF, 'ZHS16GBK')));

  utl_smtp.write_raw_data(mail_conn,utl_raw.cast_to_raw(convert('Content-Transfer-Encoding:base64'||utl_tcp.CRLF,'ZHS16GBK')));

  utl_smtp.write_data(mail_CONN, UTL_TCP.CRLF);

  --附件二进制流

  BEGIN

  --把附件分成多份,这样可以发送超过32K的附件

  L_FILEPOS := 1;

  --CREATE OR REPLACE DIRECTORY U_FIEL AS '/data/book/'

  --qq.xls附件放在ORACLE服务器/data/book/下,注意大写

  L_FIL := BFILENAME('U_FIEL', 'qq.xls');

  L_FILE_LEN := DBMS_LOB.GETLENGTH(L_FIL);

  L_MODULO := MOD(L_FILE_LEN, L_AMT);

  L_PIECES := TRUNC(L_FILE_LEN / L_AMT);

  IF (L_MODULO <> 0) THEN L_PIECES := L_PIECES + 1; END IF;

  DBMS_LOB.FILEOPEN(L_FIL, DBMS_LOB.FILE_READONLY);

  DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF);

  L_DATA := NULL; FOR I IN 1 .. L_PIECES LOOP L_FILEPOS := I * L_AMT + 1;

  L_FILE_LEN := L_FILE_LEN - L_AMT;

  L_DATA := UTL_RAW.CONCAT(L_DATA, L_BUF);

  L_CHUNKS := TRUNC(UTL_RAW.LENGTH(L_DATA) / L_MAX_LINE_WIDTH);

  IF (I <> L_PIECES) THEN L_CHUNKS := L_CHUNKS - 1;

  END IF;

  utl_smtp.write_raw_data(MAIL_CONN, UTL_ENCODE.BASE64_ENCODE(L_DATA));

  L_DATA := NULL;

  IF (L_FILE_LEN < L_AMT AND L_FILE_LEN > 0) THEN L_AMT := L_FILE_LEN;

  END IF;

  DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF);

  END LOOP;

  DBMS_LOB.FILECLOSE(L_FIL);

  EXCEPTION WHEN OTHERS THEN DBMS_LOB.FILECLOSE(L_FIL);

  utl_smtp.WRITE_DATA(mail_CONN, UTL_TCP.CRLF);

  RAISE;

  END;

  --结束处理二进制附件

  --关闭连接

  utl_smtp.close_data(mail_conn); utl_smtp.quit(mail_conn);

  exception when utl_smtp.transient_error or

  utl_smtp.permanent_error then utl_smtp.quit(mail_conn);

  raise_application_error(-20000, sqlerrm);

  when others then

  utl_smtp.quit(mail_conn);

  DBMS_OUTPUT.put_line(sqlerrm);

  end;

  EBS配置文件(Profile)常用设置

  IE打不开EBS

  ①症状:一直停留在EBS弹出式窗体,显示正在加载FORMS。

  解决:安装SUN JDK1.4,并将JVM.DLL替换掉X:\Program Files\Oracle\JInitiator 1.3.1.21\bin\hotspot

  ②症状:无法查看工作流状态图(view datagram)

  解决:安装微软的虚拟机msjavx86.exe。

  获取EBS的查询语句

  1.帮助=>诊断=>检查

  2.在块中输入SYSTEM、在字段中输入LAST_QUERY,就可以得到查询的SQL语句。

6
相关文章