这个问题再网上有很多答案,也测试用的,仍没有解决问题;
需求: 对库存表的增删改触发执行物资主表单价的更新;
条件: 1.根据先进先出,这个单价是最新进库的单价
       2.这个单价还的是保证其数量不为0 的情况下;
create or replace trigger kcdanjia_trigger
  after update or insert or delete on gmkucunxinxi
  for each row
     --库存先进先出更新物资主表单价DECLARE
         danjias number(14,2);
begin
     --提取先进的并且数量大于0的库存物资单价
      select g.danjia into danjias
       from gmkucunxinxi g
      where g.kucunid = (select min(kucunid)
                           from gmkucunxinxi
                          where wuzimingcheng = :new.wuzimingcheng
                            and shuliang > 0);      dbms_output.put_line(danjias);
       dbms_output.put_line(:new.wuzimingcheng);     --把单价更新到物资主表
     update GMWUZIXINXI set danjia =  danjias where WUZI_ID = :new.wuzimingcheng  ;end;主要报错:gmkucunxinxi 表发生变化,触发器/函数不能读它;后期也根据网上说的:你这报错是因为变异表的问题,触发器尝试读取正在发生改变的表时都会报这个错误。以及:new,:old的用法问题 : insert是插入数据,所以只会有new,
                         delete是删除数据,所以只会有old,
                          update是更新数据,所以new和old都有就改成这种形式的:
 
DECLARE
         danjias number(14,2);
         ids number(10);
         wuzimingchengs  number(10);
begin
     if inserting then
     wuzimingchengs := :new.wuzimingcheng;
     dbms_output.put_line(wuzimingchengs);
     select kucunid into ids
     from gmkucunxinxi
     where wuzimingcheng = 318
           and shuliang > 0 and rownum=1;         dbms_output.put_line(ids);
      end if;含有inserting,updating,delete判断的形式,结果也是一样;
现在我也尝试了变 行级触发器 为 语句级触发器,但关键我还必行的用到 库存表更新时的数据;
但是 new old 又不允许出现在表级触发器中,也是个问题现在只能向我一直相信的CSDN的各位大神们伸出援手了,看看具体是什么情况?
oracl

解决方案 »

  1.   

    时间有点急,也没怎么排版,大家请原谅,有什么问题我可以详细的说明的经过刚才测试,我现在在触发器的执行体(begin)里写只要关于表的sql就报错,无论这条sql多么的简单就是说不能用触发的表,触发器尝试读取正在发生改变的表而报的这个 触发器/函数不能读它 的错,
    可关键我的提取这个触发表里的数据啊,怎么解决,望大神们帮忙
      

  2.   

    刚才看到网上有这么一句:
    ORA-4091错误是在点火触发器时引发的而不是在创建该表时引发的!!!
     要消除变化表的错误,不能用行级触发器中查询它,但可以在语句级触发器中查询它。
    可关键是用语句级触发器就不能用new old了,可是我要用到这个更新的表记录中的数据的
    还是没解决啊,大神快快现身吧
      

  3.   


    http://blog.csdn.net/ziwen00/article/details/8574127
      

  4.   


    测试就是新增一条库存记录:insert into gmkucunxinxi
      (kucunid, cangku, shuliang, danjia, jine, linjiekucun, WUZIMINGCHENG)
    values
      (gmkucunxinxi_kucunid.nextval, '1', 13, 2, 26, '8', 318)
      

  5.   

    /*DROP TABLE KUCUN;
    DROP TABLE WUZI;*/--创建表  库存表
    CREATE TABLE KUCUN(
        GOODSID NUMBER(10), --货物
        PURCHASETIME DATE,--进货时间
        PRICE NUMBER(20,4)  --货物单价
    );
    /
    --创建表 物资表  (被更新的主表)
    CREATE TABLE WUZI(
        GOODSID NUMBER(10), --货物
        PRICE NUMBER(20,4)  --货物单价
    );
    /--生成测试数据
    BEGIN
        FOR I IN 1..10 LOOP
            INSERT INTO KUCUN VALUES(I,SYSDATE - NUMTODSINTERVAL(I,'HOUR'),I+I*0.1);
        END LOOP;
        COMMIT;
    END;
    /SELECT * FROM KUCUN;--生成测试数据
    BEGIN
        FOR I IN 1..10 LOOP
            INSERT INTO WUZI VALUES(I,I);
        END LOOP;
        COMMIT WORK;
    END;
    /SELECT * FROM WUZI;--触发器,写入一条心的GOODSID为1的信息,然后更新主表,创建触发器
    CREATE OR REPLACE TRIGGER TRI_KUCUN
        --在插入之前
        BEFORE INSERT OR UPDATE ON KUCUN
        FOR EACH ROW
    DECLARE
        N_PRICE KUCUN.PRICE%TYPE;
    BEGIN
        --得到插入数据之前的最早的价格
        --比如本次插入的是13,但是实际上查出来的是1-10的GOODSID日期最小的价格,而不是1-10包含13
        BEGIN
            SELECT DISTINCT FIRST_VALUE(T.PRICE) OVER(PARTITION BY T.GOODSID ORDER BY T.PURCHASETIME) 
                INTO N_PRICE
             FROM KUCUN T
            WHERE T.GOODSID = :NEW.GOODSID;
           EXCEPTION
             --处理NO_DATA_FOUND异常
             --用于处理那种,先进先出,但是进去的已经被处理掉了的情况,即所有的库存表中的记录都已经被更新到物资表中
             WHEN NO_DATA_FOUND THEN
                 N_PRICE:=:NEW.PRICE;
         END;
         
         --更新物资表的GOODSID的价格
         UPDATE WUZI
         SET WUZI.PRICE = N_PRICE
         WHERE WUZI.GOODSID = :NEW.GOODSID;
         --如果物资表的GOODSID不存在的话,则插入
         IF SQL%ROWCOUNT <1 THEN
             INSERT INTO WUZI(GOODSID,PRICE) VALUES(:NEW.GOODSID,N_PRICE);
         END IF;
         
    END;
    /--测试数据  
    --插入GOODSID为1,PRICE为100,应该更新为1.1
    INSERT INTO KUCUN VALUES(1,SYSDATE,100);
    SELECT * FROM WUZI;
    --插入GOODSID为13,PRICE为100,应该插入一条新的为100
    INSERT INTO KUCUN VALUES(13,SYSDATE,100);
    SELECT * FROM WUZI;
      

  6.   

    大致的思路是这样子的:
    after表示触发器在插入、更新或者删除之后才会调用下面的语句块,但是当前的事务还没有被提交,所以为了保证数据的一致性,Oracle是不会让你操作一个变动了的表,因此提示你所遇见的错误。
    就将after修改为before,这样在对库存表进行变动之前,就可以得到你想要的信息,然后缓存起来,使用:NEW.获取最新插入的数据与缓存的数据作比较,然后去更新物资表。
      

  7.   

    before是操作之间运行,此时的事务还没打开,所以表里的内容是固定的。after是操作之后运行,此的事务已经打开,但是还没有提交,所以表里的内容是活的呵呵 真巧都发现了这个问题,这在测试中,哈哈,谢谢大哥
      

  8.   


    另外:在TRIGGER的语句块里面,可以使用类似于 IF INSERTING THEN V_ACTION := 'INSERT';
    ELSIF UPDATING THEN V_ACTION := 'UPDATE';
    ELSIF DELETING THEN V_ACTION := 'DELETE';
    ELSE V_ACTION :='OTHER';
    END IF;的语句来区分锁进行的操作,可以解决上面的OLD NEW的问题
      

  9.   

    领导说通过流程的联动设置来解决这个问题: 最先进来的数量大于0的单价;
    就这一句话我之前的努力就这么完了,我就是一个苦命的娃啊现在问题又来了:这条sql的问题此条sql主要实现的功能:查物资库存表依照先进先出原则查询最先进库存的并且数量大于0的物资单价;
    正常情况下     
        select g.danjia
           from gmkucunxinxi g
            where g.kucunid = (select min(kucunid)
                                 from gmkucunxinxi
                                where wuzimingcheng = 203
                                  and shuliang > 0); 这条sql就能解决问题;
    可结合流程联动设置的限制问题,代码中这个wuzimingcheng = 203,已经随着浏览框默认加到sql的关联
    条件上了,至于加到了最前面还是最后面还不清楚,先假设加载条件的最前面吧;
    可是我的子查询里的 这条wuzimingcheng = 203怎么办了????经改后,成这样:select k.danjia from gmwuzixinxi g,gmkucunxinxi k 
    where g.wuzi_id=k.wuzimingcheng and k.shuliang > 0 and rownum = 1其实后面默认加上如:and k.WUZIMINGCHENG = 203,本思路是 这两个物资主表和库存表关联上了,库存数量也大于0了,默认是正序,选第一行,就能实现
    先进来的 库存id最小的;可是却忽略了 这个默认是正序的也只是在 order by k.kucunid 后面什么不写的情况下,这时默认是正序的;
    但加上order by ,假设这and k.WUZIMINGCHENG = 203,是加在前面的先不考虑但仍有个关键问题select k.kucunid,k.danjia
      from gmwuzixinxi g, gmkucunxinxi k
     where g.wuzi_id = k.wuzimingcheng
      and k.WUZIMINGCHENG = 203
       and k.shuliang > 0
       and rownum = 1
       order by k.kucunid这条sql显示的不是正序排列完取id最小的第一条,而是随机的,谁都有可能是第一条;
    现在正在想办法解决,望大神,大哥们再帮我想想,折腾一天了,脑袋都冒烟了!!!
      

  10.   


    可以使用Oracle的分析函数来解决
      

  11.   


    大哥,基本学习了分析函数,功能很强大,但分析语句确实与我的联动设置不符合啊,这个联动设置已经默认为简单sql的形式,select * from a,b where a.id=b.aid and ...这种形式的,
    悲剧,不过仍要谢谢大哥,希望大哥再出谋划策啊
      

  12.   

    你这是什么工具啊..
    没有填写按哪些字段排序的功能吗?
    看看源码吧,你怎么知道到底是怎么order by的.
    都是你的YY
      

  13.   


    现在已经落实无法解决,已经向上审批了,
    在这特别感谢ziwen大哥,希望给小弟个机会交个朋友
    方面的话可以把QQ发到我邮箱:[email protected]
    以后有问题还的向大哥多多请教了,谢谢再次感谢!!!