PLSQL - 触发器:无法修改映射到非密钥保留表的列

时间:2009-04-27 00:41:34

标签: sql plsql triggers

我想要做的是当在concessions_sold表中放置订单(使用插入)时,使用触发器更新库存表中销售的数量。我承认我吮吸PLSQL所以我不确定我是否正确地采用了这种方式。我得到的错误是:


SQL> insert into concessions_sold
  2  values(33, 104, '26-Apr-09', 50);
insert into concessions_sold
            *
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table

我的代码:


create or replace trigger LabEx5_1 after insert on Concessions_sold
for each row
begin
if inserting then
update
( 
select i.quantity 
from inventory i, concessions_sold cs, concession c
where i.inventory_id = c.inventory_id and c.concession_id = cs.concession_id
)
set quantity = :new.quantity;
end if;
end LabEx5_1;
/

3 个答案:

答案 0 :(得分:0)

您正在尝试更新触发器中的连接视图,这对于何时可以执行此操作有几个限制;有关详细信息,请参阅Oracle documentation

这个更新应该做你想要实现的目标:

UPDATE inventory i 
 SET i.quantity = :new.quantity 
 WHERE i.inventory_id = 
  (SELECT c.inventory_id 
    FROM concessions c 
     WHERE c.concession_id = :new.concession_id)

答案 1 :(得分:0)

首先,如果您使用“For Each Row”触发器,那么您不能在整个表上操作,只需要一行,所以

select i.quantity 
from inventory i, concession c
where i.inventory_id = c.inventory_id and c.concession_id = cs.concession_id

应改为

select i.quantity 
from inventory i, concessions_sold cs, concession c
where i.inventory_id = c.inventory_id and c.concession_id = :new.concession_id

其次,更新应该是这样的:

update inventory
set quantity = :new.quantity
where inventory_id = ( 
  select inventory_id from concession c where concession_id = :new.concession_id 
) ;

因此触发器应如下所示:

create or replace 
trigger LabEx5_1 after insert on Concessions_sold
for each row
begin
  if inserting then
    update inventory
      set quantity = :new.quantity
    where inventory_id = ( 
      select inventory_id from concession c 
      where concession_id = :new.concession_id 
    ) ;
  end if;
end LabEx5_1;

答案 2 :(得分:0)

一些事情:

  1. “插入后”和“如果(插入)”是重复的。删除“If(插入)”是不必要的,因为您的触发器仅限于AFTER INSERT。只需添加更多代码即可阅读。

  2. 看来你在卖东西时试图降低你的库存。我没有看到你真的这样做。

  3. 这是embeded查询没有与之关联的密钥。 (这是你的错误信息来自)。

  4. select i.quantity 
    from inventory i, concessions_sold cs, concession c
    where i.inventory_id = c.inventory_id and c.concession_id = cs.concession_id
    
    1. 您没有where子句,并且您的内联选择不会限制从库存表中返回的行。如果您确实这样做了,那么您将更新清单表中的每一行。
    2. 使您的实际更新条款有效。

        UPDATE (
          SELECT **i.inventory_id**, i.quantity   
          FROM Inventory i
            , Concessions_sold cs
            , Concessions c   
          WHERE i.inventory_id = c.inventory_id   
          AND c.concession_id = **:NEW.concession_id** 
        )
        SET quantity = :new.quantity
      

      现在它的工作存在一些问题: 1.不需要链接表。 2.内联SQL使得这个UPDATE语句更难以阅读,因此将来更难修改。

      我会更明确:

      
      UPDATE Inventory
      SET quatity = quanaity - :new.quanity
      WHERE inventory_id IN (
        SELECT inventory_id
        FROM Conessions c
        JOIN c.concession_id = :NEW.concession_id
        )
      

      显然,没有检查库存数量是否确实存在,您可能需要考虑其他因素。

      所以你的新触发器看起来像这样。

      
      CREATE or REPLACE TRIGGER LabEx5_1 AFTER INSERT ON Concessions_sold
      FOR EACH ROW
      BEGIN
        UPDATE Inventory
        SET quatity = quanaity - :NEW.quanity
        WHERE inventory_id IN (
          SELECT inventory_id
          FROM Conessions c
          JOIN c.concession_id = :NEW.concession_id
          );
      END LabEx5_1;