2016-01-23 103 views
0

我试图创建一个触发器,但是我已经了解到我无法将它设计为在我第一次尝试中,我将在下面显示它。这会导致一个'变异表'错误,因为它正在被修改时从表中选择。实际上,在一次只插入一条记录时实际上不会导致此错误,但是当我一次插入多条记录时,它会发生此错误。Oracle SQL创建触发器以增加每行的序列号

触发器的用途是计算表中客户等于要插入的客户的记录数,并将新的order_num值设置为count + 1。我也有一个由触发器设置的公钥值,它是从一个序列中抽取的。一旦删除触发器的order_num部分和关联的SELECT,这部分工作正常。我怎样才能达到我在这里想要做的?提前致谢。

CREATE OR REPLACE TRIGGER t_trg 
    BEFORE INSERT ON t 
    FOR EACH ROW 
DECLARE 
    rec_count NUMBER(2,0); 
    BEGIN 
    SELECT COUNT(*) INTO rec_count 
    FROM t 
    WHERE customer_id = :NEW.customer_id; 

    :NEW.order_num:= rec_count+1; 
    :NEW.order_pk_id:= table_seq.NEXTVAL; 

    END; 
+0

有几个问题。首先,你为什么要这样做,而不是使用合成密钥(即序列)?那么,假设你有一个有效的需求,任何解决方案将取决于使用情况?有多少客户?每个客户有多少个订单?您可以同时为每个客户处理多个订单吗?周转时间是多少? – APC

+0

一个序列听起来很棒,但是我相信我将不得不为每个插入的新客户创建一个新的序列 - 每年约100K。 我使用客户,订单等作为抽象 - 我没有真正处理客户和订单。 '客户'每批不会有'1'的订单 - 可能不在同一年内。因此,我的原始方法只计算现有表中的值,并忽略正在处理的批次中的内容。最多只有百分之几的人会在一生中拥有2+'订单'。我最关心的是CPU时间,因为我在生产服务器上这样做。 – mb158127

+1

为什么每次插入行时都要计算行数?这是死的缓慢,不会扩展,但最糟糕的是:它会存储错误的行数。两个并发事务将在':new.order_num'中得到**相同的**值。 –

回答

0

两个触发器和临时表方法可以为您寻找解决方案,防止突变表错误。然而,表现很可能会受到影响。

create global temporary table cust_temp(customer_id number, cust_cnt number); 

create or replace trigger t_trig1 
before insert on t 
declare 
begin 
    insert into cust_temp select customer_id, count(*) from t group by customer_id; 
end; 
/

CREATE OR REPLACE TRIGGER t_trg2 
    BEFORE INSERT ON t 
    FOR EACH ROW 
DECLARE 
    rec_count number; 
    BEGIN 
    BEGIN 
     SELECT cust_cnt INTO rec_count 
     FROM cust_temp 
     WHERE customer_id = :NEW.customer_id; 
    EXCEPTION when no_data_found then rec_count := 0; 
    END; 
    :NEW.order_num:= rec_count+1; 
    :NEW.order_pk_id:= table_seq.NEXTVAL; 
     update cust_temp set cust_cnt = rec_count + 1 
     where customer_id = :NEW.customer_id; 

    END; 
/