oracle ebs 工作心得

更新时间:2024-06-29 12:32:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

PL/SQL 部分

select a.sno,a.sname , (select a.sname from dual a where rownum =1)

haa from song a;

--对于括号里的查询 select 列表里有个a 到底是指的是里面dual 还是外面的song表呢 当 dual 有 字段sname时 a.sname 只的就是dual 如果 dual根本没有字段sname 它会去外层查询 的表里找 如果 还没有 才会报错 有的话 就指的是外面的表 所以 最好明确 要指的是谁 这种情况简称最好保持 不一致

对于用外连接 还是用内连接的一些理解:

像此处 我商品信息基本表里保存了一个“外键”商品类别ID(其实没有真正的建立外键),用以关联外键信息(商品名称等等),我觉得我在建立这个块视图的时候 还是用外连接好, 理由如下:

我们先查看我们的商品类别的快速编码信息 画面如下:

现在我们删除第2行 我们发现我们成功了(我们也应该让他成功 不能因为这个电子类别 已经被引用了而不允许删除 再说 如果要这么做 也不科学 到时系统大了 我们也不确定这个快速编码会被哪些表引用 我们当然可以通过外键来实现 当被引用时不允许删除 但这样就不够灵活了 我们的数据库也不提倡建立外键),画面如下:

假如 如果我用内连接来连接类别 这时 我们在商品信息的form里将查不到以前用到过电子这一类别的 所有记录行了

分析如何判断是否用内连接还是用外连接: 1:我们可以分析哪个表的记录更重要 像这里我们的商品信息是更重要的 由于种种原因 可能商品类别会被篡改,删除等等 我们不能因为这些 就把原先有的商品信息过滤掉 不让它们显示出来

2:我们应该分析需求 ,比如我们要查看订单信息 想知道有多少张订单 即使没有订单行业没关系 或者 我只关心 订单头的信息 行的记录并不是很关心(也不是完全不关心 这里假设 只是稍微“关心”一下) 此时我们也应该用外连接

什么时候用内连接: 我们要求“查出来的结果”相互依存 有a必须有b 比如b表的信息很重要 有b必须有a 比如不然b记录作废 则此时我们就必须用内连接了 举例如下:

我们要查看某某商品的销售情况 如多少数量等等 比如订单头表为head 行表为line

我们应该写如下语句 select count(qty) from head h, line l where h.head_id=l.head_id and item_id=’abc’

理由:(head 在左 line 在右)

1 如果有头记录 没有行记录 我们直接排除 因为我们要数量 没有行记录则没有数量 这样我们排除掉了用左外连接

2:如果有行记录 没有头记录(正常情况,系统是不应该有这情况的) 像这样的行记录我们应该是认为无效的 作废的 所以右外连接 也不可取 3:根据上面的分析 我们应该用内连接

我觉得 我们到底用什么连接 应该视我们需要什么样的数据? 是否允许 有 a表的记录 然后没有b表的记录? 还是反之? 还是必须都互相有?

像上面的商品信息 关联类型信息一样,我们可以这样问自己: 1:我们的结果集里 当没有类型信息是 商品的信息还显示吗?

2:还是我们要的结果集里 必须有类型信息 不然 这样的商品信息不显示? 3:我们不应该这样问,因为数据库里 有商品信息表里是 肯定会有类型信息的 假设真这样的话 用内连接 和用外连接其实就结果一样了(商品信息表 内连接商品类型信息 和商品信息左外连接商品类型信息)

像第一个例子:我们不应该让小小的不重要的商品类型信息 影响到 商品信息的查看 商品信息在那form里是最主要的信息 用户想看到的信息 像第2个例子:我们需要数量 但是有过只有订单头 又有何用? 如果有订单行 没有头?这信息就是非法的 无效的 所以 这样的我们就用内连接

对oracle 连接写法的一些归纳 一些易错的地方的分析 注意点1:

有一个表 song 记录如下:

有一个表song1记录如下:

我们执行如下查询

select a.sno as a_sno,b.sname as b_sname from song a, song1 b where a.sno=b.sno(+) 结果如下:

结果使我们预想的那样 没有错 然后我再执行如下查询:

select a.sno as a_sno,b.sname as b_sname from song a, song1 b where a.sno=b.sno(+) and b.sname<>'flash' 结果如下:

为什么会这样呢? 是因为我们加的b.sname<>'flash' 条件 是在表song和song1通

过连接a.sno=b.sno(+) 执行完之后 再筛选的

(那这里为什么第3行没有出来 是因为 第3行的B_SNAME 为null null也是不等于‘flash’的 null 是未知的 不等于任何值 也不“不等于”任何职)

分步:

连接完之后的结果集为:

再b.sname<>'flash' 筛选

结果集当然就变成这个了 如下:

(那这里为什么第3行没有出来 是因为 第3行的B_SNAME 为null null也是不等于‘flash’的 null 是未知的 不等于任何值 也不“不等于”任何职)

它并不是先通过b.sname<>'flash'去筛选 song1 表 再 连接的 如果是先筛选的话 其语句应该等同于下面的语句:

select a.sno as a_sno,b.sname as b_sname from song a, (select * from song1 where sname<>'flash') b where a.sno=b.sno(+)

其结果为:

根据以上 我们得出的结论是 b.sname<>'flash' 是连接结果集出来之后 再对那个结果集进行筛选.

注意点二:

如果我们所加的条件是针对左边的表 即

select a.sno as a_sno,b.sname as b_sname from song a, song1 b where a.sno=b.sno(+) and a.sname<>'flash' 其执行效果 和

select a.sno as a_sno,b.sname as b_sname from (select * from song where sname<>'flash') a, song1 b where a.sno=b.sno(+) 其结果集都为:

因为 左边的表为基表 先 筛选基表 再去连接 还是先连接 再筛选连接结果 其结果不难想象应该是一样 只是执行顺不一样而已

如果是内连接呢

select a.sno as a_sno,b.sname as b_sname from song a, song1 b where a.sno=b.sno and a.sname<>'flash' 的 执行结果 和

select a.sno as a_sno,b.sname as b_sname from (select * from song where sname<>'flash') a, song1 b where a.sno=b.sno 的执行结果也是一样的 (虽然 执行的顺序不同)

根据上面 我得出的结论是:

1:类似如 “其中一个表的字段(或相关的)= (或其他运算符)一个和另一个表无关的”where条件 他是不参与连接的 他是在连接后 再对连接结果进行筛选的 2:写左连接时(左表a 右表b) 如果 是进一步对a表进行删选 如a.id=123 等等 其和先对a表进行筛选 再来和b左连接 其效果是一样的 (右连接也一样)

如果是加 b.id=123这样的条件 我们就要注意了 我们就要分析 到底是要先对b进行筛选 还是 对最终结果的筛选 因为他们的执行结果是不一样的 不注意就会写错 如果 是要先 筛选b 再连接 我们就要这样写 123=b.id(+);(其实我们可以理解为 123是a表中的一个字段 中的值 对于a表每一行 其值都为123 如果我们是要对最终结果的筛选 直接写成123=b.id就好了

3:通过上面2的分析 对外连接的辅助表( 左连接时的右表 右连接时的左表) 添加类似id=123的where条件时 我们才需要格外主要 是否要在id后面加(+)号 因为 其他情况 其结果是一样的

补充说明:

现在执行如下查询:

select a.sno as a_sno, b.sname as b_sname from song a ,song1 b where a.sno=b.sno(+); 其结果为:

如果我只要连接 b表中 sname=’flash’的记录呢?即我要得出如下结果集 :

查询语句该怎么写呢 可以这样写:

select a.sno as a_sno, b.sname as b_sname from song a ,song1 b where a.sno=b.sno(+) and 'flash'=b.sname(+);

这里我们可以理解为 ‘flash’为a存在一列,而且其列值总为flash 即上面语句类似如下:

select a.sno as a_sno, b.sname as b_sname from (select 'flash' col ,song.* from song) a ,song1 b

where a.sno=b.sno(+) and a.col=b.sname(+);

如果我要限制左边表 我要的结果集是: 只有a表中sno=5的才去连接 b表中的sno 该怎么写呢? 我们这样写是错:

select a.sno as a_sno, b.sname as b_sname from song a ,song1 b where a.sno=b.sno(+) and a.sno=5(+) ;

根据上面的变通写法 我们可以把5理解为b中存在一列 其列值总为5,即我们可以这样写:

select a.sno as a_sno, b.sname as b_sname from song a , (select 5 as col , song1.* from song1) b

where a.sno=b.sno(+) and a.sno=b.col(+) 我们得到的结果集为:

这正是我们要的结果.

然后 我修改第3行的 采购单价 99 为100 画面如下:

(之前我错误的认为 每次 on_lock之后 记录都自动解锁了 认为是form自动维护的 此为错误的想法 只要执行了 on_lock 里面锁定的记录 并不会被解锁 此我通过如下验证, 上面我把 第3行的99 改为100 时 form执行了 onlock(里面有锁此记录) 然后 我在外面执行update cux_porder_lines_syb set goods_price=88 where line_id=72;(此语句试图修改第3行 ) 然后 此sql语句阻塞(被form里的onlock锁定了) 所以 即证明我之前的认识是错误的 )

然后我在外面用sql语句手动修改 头表的订单名称 语句为:

update cux_porder_heads_syb set order_name='song买衣服' where order_id=1; commit; 此语句 把

改为 song买衣服

然后我们再保存form(之前我们把第3行的 采购单价 99 修改为100了) 截图如下:

此时 我们发现 第三行的修改成功了 但是 我们在外面用sql 修改的头块的订单名称没变 这是因为我们没有查询出最新的数据库信息 现在我们查出 如下画面:

结论:根据上面演示 我们发现 如果 有人 在修改 行表 form的设计(或我们的现有代码)允许去操作头表 我觉得这会带来 很多很多问题 特别是 多用户环境下使用时 会导致系统数据崩溃

举例如下:我们知道 删除头记录的时候 如果有行记录 就不允许删除

所以我假设 现在有 一条头记录a 没有行记录 现在某一用户甲 正在对a记录 插入对应的行记录 而此时 另一用户乙 也查询出了头记录a 此时 数据库里 还没有a对应的的行记录 现在乙删除头记录a 他成功了 现在甲要插入的行记录b也输入完毕 点击保存 并也他也成功了 当他再去重新查询头的a记录时 已经找不到了 我们知道此时 数据库里已经没有a记录 而 行记录b存在于数据库 但是他却称了“没爹的孩子” 根据我们的form设计 我们在form上是查不到b的 并且我们也一般认定 没有头记录的行记录 一般是无效的 或者错误的 一般不处理这样的行记录 作废处理 这只是我举的一个例子而已 相应带来的问题还会很多 提议:

分各种情况分析:

新增头块记录:不锁任何记录(不可虑其他特殊情况等等)下同。 修改头记录:锁定对应头记录(现在的form里已经有这个)。 删除头记录:锁定对应头记录(现在的form里已经有这个)。

新增行记录:锁定对应头记录 (失败则不允许新增)。

修改行记录:先去锁定对应头记录,再去锁定对应行记录(后者现在的forms里已经考虑了这个)。

删除行记录:先去锁定对应头记录,再去锁定对应行记录(后者现在的forms里已经考虑了这个)。

比如我们照上面的做了, 现在再对行进行修改,删除,或者 新增 (我们已经锁了对应的表头) ,当如果有其他用户打开了同一画面 的相同数据 正去试图修改头记录 他将被告知“资料正在被别人使用” 然后禁止他修改。其实 观点很简单,就是像这样的头行结构 一对多的关系 同1个画面(即头记录相同) 我们在同1时刻理应只允许有一个用户 修改 而我们现在系统好像 允许 同时有2个用户在修改,一个修改头记录 另一个修改行 这样的“并发操作”应该是不应该被允许的

疑问: on_lock 报错 在块的onlock事件中写 fnd_message.debug(‘ abc’) 当是中文字触发 on_lock触发器时 程序会瘫痪 不加fnd_message.debug(‘ abc’) 中文字触发是不会瘫痪的

On_lock 在第一次修改界面上的值时触发 紧接着当前那次的修改 后面的改变界面上的值不会再触发 因为 已经锁过了 如果成功 其他人是不可能再修改的 就无需再去判断 是否界面上的值和数据库里的值一致了。

在form中删除记录时也会触发 on_lock

按F11 触发的触发器:

(1)WHEN-CLEAR-BLOCK

(2)WHEN-NEW-RECORD-INSTANCE

(3)WHEN-NEW-ITEM-INSTANCE 理解:

假设有如下画面:

下面我们按F11查询头块: 画面变成:

它清空了头块的记录:所以它执行了WHEN-CLEAR-BLOCK

它新建了一条记录 所以它执行了 WHEN-NEW-RECORD-INSTANCE

光标进入了订单编号 所以 它应该执行了 WHEN-NEW-ITEM-INSTANCE

Bell; 可以发出一个提示音

删除一条记录时:

(1)ON-LOCK

(2)WHEN-REMOVE-RECORD (3)KEY-DELREC

(4)WHEN-NEW-RECORD-INSTANCE

(5)WHEN-NEW-ITEM-INSTANCE

首先 按照惯例 还是会去on-lock 记录 完成 锁定 和 数据库数据的对比 如果和数据库的数据一致 则锁定成功 否则 锁定失败

然后移除记录 然后会新建一个记录实例 光标会进入到某一项 即会触发 WHEN-NEW-ITEM-INSTANCE

此处的WHEN-NEW-ITEM-INSTANCE 是项级触发器

按CRRL+F11执行查询时:

(1)WHEN-CLEAR-BLOCK (2)PRE-QUERY

(3)WHEN-CLEAR-BLOCK

(4)POST-QUERY(每查一条记录,触发一次)

(5)WHEN-NEW-RECORD-INSTANCE (6)WHEN-NEW-ITEM-INSTANCE

POST-QUERY每查一条记录,触发一次 然后再查下一条 在form上看到的效果是 显示出一条 然后 执行POST-QUERY 然后再显示一条 再POST-QUERY… …

如下图所示:

点击确定后:

从查询状态(F11)转为输入状态(F4)时:

(1)WHEN-CLEAR-BLOCK (2)KEY-EXIT

(3)WHEN-NEW-RECORD-INSTANCE (4)WHEN-NEW-ITEM-INSTANCE 理解:先清除 再退出查询状态 然后 新建一个记录 和进入第一个可导航的项时新建项实例

手电筒查询过程:

(1)QUERY_FIND(BLOCK级)

输入查询条件后,点击“查询”按钮: (2)WHEN-CLEAR-BLOCK (3)PRE-QUERY

(4)WHEN-CLEAR-BLOCK (5)POST-QUERY

(6)WHEN-NEW-RECORD-INSTANCE (7)WHEN-NEW-ITEM-INSTANCE

点击“New”时:

(1)WHEN-NEW-RECORD-INSTANCE (2)WHEN-NEW-ITEM-INSTANCE

点击F4关闭时:

(1)KEY-EXIT (2)POST-FORM

17.点击“Close Form”按钮关闭时:

(1)KEY-EXIT (2)POST-FORM

18. 点击“Translations”按钮时:

(1)TRANSLATIONS

19.点击小叉号关闭时:

(1)WHEN-WINDOW-CLOSED (2)CLOSE-WINDOW (3)KEY-EXIT

(4)POST-FORM

先关闭窗体 再关闭 form 因为 一个form 窗体有可能有多个 窗体属于form

20.选中LOV列表:

(1)KEY-LISTVAL

(2)WHEN-NEW-ITEM-INSTANCE 理解:选择值后 光标会进入后一个可导航的项 所以会触发WHEN-NEW-ITEM-INSTANCE

21.选中记录前面的小条时:

(1)WHEN-NEW-RECORD-INSTANCE

(2)WHEN-NEW-ITEM-INSTANCE(数据项级) (3)WHEN-NEW-ITEM-INSTANCE

22.光标上下移动时

(1)WHEN-NEW-RECORD-INSTANCE (2)WHEN-NEW-ITEM-INSTANCE

用代码改变项值,会触发WHEN-VALIDATE-ITEM:

当在项a中的触发器:WHEN-VALIDATE-ITEM 中用代码改变项b中的值时 当光标从项b(不再做任何输入或改变)中离开后 会触发项b的触发器:WHEN-VALIDATE-ITEM(如果有的话):

如下图所示:

输入订单名称 然后离开 触发了WHEN-VALIDATE-ITEM 在该触发器有如下代码:

fnd_message.debug('WHEN-VALIDATE-ITEM order_name 改变 采购员的值为 abc 验证是否会触发 采购员的WHEN-VALIDATE-ITEM ');

:CUX_PORDER_HEADS_SYB_V.purchaser:='abc';

然后光标进入了采购员项 离开后 触发了 WHEN-VALIDATE-ITEM 该触发器中有如下代码:

fnd_message.debug('okay, it''s me ,采购员');

fnd_message小记:

订单名称中的触发器WHEN-VALIDATE-ITEM代码如下:

if lengthb(:CUX_PORDER_HEADS_SYB_V.order_name)<4 then fnd_message.set_name('FND','订单名称太短'); fnd_message.error;

raise form_trigger_failure;

end if;

如果输入的订单名称字节少于4 则给出提示 认为不合法 并且不允许离开 raise form_trigger_failure; 抛出异常 把 光标留在当前项

帮助主题说 如果WHEN-VALIDATE-ITEM失败 则:If fired as part of validation initiated by navigation, navigation fails, and the focus remains on the original item.

画面如下:

fnd_message.set_string('订单名称选择:YES=0001, NO=0002,CANCEL=0003'); result:=fnd_message.question('YES','NO','CANCAL',1,2,null); if result=1 then

:CUX_PORDER_HEADS_SYB_V.order_name:='0001'; elsif result=2 then

:CUX_PORDER_HEADS_SYB_V.order_name:='0002'; end if;

的执行效果如下:(char(10)可以代表换行)

1 FND_MESSAGE.show 与 FND_MESSAGE.debug 效果相同,用于把信息以最基本的方式显示给用户。

2. FND_MESSAGE.hint

这种方式不会弹出对话框给用户,而是显示在左下脚的状态栏上面 3. FND_MESSAGE.error

以Error信息的方式显示给用户 4. FND_MESSAGE.warn

以选择信息的方式显示给用户,可以选择Ok或者Cancel,返回值分别是TRUE和FALSE if FND_MESSAGE.warn then fnd_message.debug('True'); else

fnd_message.debug('False'); end if;

执行效果如下: 点击OK会弹出 True 点击Cancel会弹出 False

Message()信息的显示问题:

在触发器中测试 如下语句的时候:

message(' song WHEN-NEW-ITEM-INSTANCE '); fnd_message.set_string( 'please select your value');

v_result:=FND_MESSAGE.QUESTION('是','否','取消',1,2);

fnd_message.debug(v_result);

发现' song WHEN-NEW-ITEM-INSTANCE ' 最后才显示 message(‘’) 应该是在触发器都执行完之后 再显示的,或者可能是 在触发器执行完后 才会去刷新画面吧

上面的 fnd_message.set_string( 'please select your value'); v_result:=FND_MESSAGE.QUESTION('是','否','取消',1,2); 执行效果如下:

按取消 其返回结果为3 当上面只定义了1,2

fnd_message.set_string( 'please select your value'); v_result:=FND_MESSAGE.QUESTION('是','否','取消',1,4); 的执行效果如下:

是为1 取消为3 否为2

WHEN-MOUSE-LEAVE的问题的发现:

我在了解这个触发器的时候 发现这个触发器 貌似不像其名字一样触发 甚至 根本就没测到过他被触发过 因为根据这个名字 应该是每次离开 不管什么情况离开 它都是应该触发的 如在一个项里 离开,但是 此触发器貌似不行 然后 类似的POST-CHANGE WHEN-VALIDATE-ITEM POST-TEXT-ITEM 却不能做到每次都触发,如果我们要 实现“每次离开 都执行一些自己的代码逻辑”该怎么办呢? 我根据执行 的list项 如果原先值为a 我改为b后 再改为a 虽然最后结果和进入前一致但是还是触发了 我大胆假设 是因为 :块.项改变了 就会执行WHEN-VALIDATE-ITEM 所以 通过这个发现我在 某一项的WHEN-NEW-ITEM-INSTANCE 写如下代码:

declare aa int ;

begin

aa:=:CUX_PORDER_LINES_SYB_V.GOODS_PRICE; :CUX_PORDER_LINES_SYB_V.GOODS_PRICE:=aa+1;

:CUX_PORDER_LINES_SYB_V.GOODS_PRICE:=aa; end ;

即可执行 无论什么情况 WHEN-VALIDATE-ITEM 这个触发器都会执行的 这就实现了类似WHEN-MOUSE-LEAVE 的功能

此方法也可以用到记录上 ,这要在 数据块理 添加一个自定义项 然后 在WHEN-NEW-RECORD-INSTANCE的时候 改变这个自定义项即可 这样 就算不改变界面项的项值 当前记录还是改变了 所以其 WHEN-VALIDATE-RECORD 总是会执行的

上面的执行结果如下所示:

现在光标进入订单明细的第一行 如下所示:

然后直接离开 如下图所示:

即无条件执行了WHEN-VALIDATE-ITEM

本文来源:https://www.bwwdw.com/article/r963.html

Top