PLSQL - триггеры: невозможно изменить столбец, который отображается в таблицу без сохранения ключа - PullRequest
0 голосов
/ 27 апреля 2009

То, что я должен сделать, - это использовать триггер для обновления количества, проданного в таблице запасов, когда заказ размещен в таблице concessions_sold (используется вставка). Я признаю, что сосу в PLSQL, так что я не уверен, правильно ли я поступаю. Я получаю ошибку:

<code>
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 голосов
/ 27 апреля 2009

Прежде всего, если вы используете триггер «Для каждой строки», вы НЕ ДОЛЖНЫ работать со всей таблицей, только с одной строкой, поэтому

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;
0 голосов
/ 27 апреля 2009

Пара вещей:

  1. "после вставки" и "если (вставка)" являются избыточными. Удалите «Если (вставка)» это не нужно, так как ваш триггер ограничен ПОСЛЕ ВСТАВКИ. Просто добавляет больше кода для чтения.

  2. Кажется, вы пытаетесь уменьшить свой инвентарь, когда что-то продается. Я не вижу, что вы на самом деле это делаете.

  3. Этот встроенный запрос не имеет ключа, связанного с ним. (Это ваше сообщение об ошибке).

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, и ваш inline-select не ограничивает строки, возвращающиеся из таблицы инвентаря. Если вы добьетесь того, чтобы это сработало, вы будете обновлять каждую строку в своей таблице инвентаризации.

Чтобы ваше действительное предложение об обновлении работало.

  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;
0 голосов
/ 27 апреля 2009

Вы пытаетесь обновить вид соединения в своем триггере, который имеет несколько ограничений, когда это можно сделать; подробности смотрите в документации Oracle .

Это ОБНОВЛЕНИЕ должно делать то, что вы пытаетесь достичь:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...