Созданный триггер в Oracle PL / SQL, похоже, ничего не делает - PullRequest
1 голос
/ 10 декабря 2011

Я пытаюсь узнать, как реализовать триггеры с использованием PL / SQL.Итак, у меня есть пример базы данных, который я собрал, и у меня есть триггер, который на мой очень неопытный взгляд выглядит так, как будто он должен работать:

CREATE OR REPLACE TRIGGER updateBeerCount
AFTER INSERT ON beerTable
FOR EACH ROW
DECLARE 
pragma autonomous_transaction;
beers_produced INTEGER;
BEGIN
    SELECT COUNT(beer_name) INTO beers_produced FROM beerTable WHERE brewery = :NEW.brewery;
    UPDATE breweryTable SET number_of_beers_produced = beers_produced WHERE brewery = :NEW.brewery;
    COMMIT;
END;
/

По сути, здесь есть две важные таблицы - beerTable, который содержит список пива с их пивоваренными заводами, и breweryTable, который содержит список пивоваренных заводов и счетчик того, сколько разных сортов пива они производят.Таким образом, number_of_beers_produced должно быть общим числом строк в beerTable, где указана эта пивоварня (пивоварня является внешним ключом в beerTable

. Поскольку этот код выполняется и не выдает никаких ошибок вкомандная строка, в которой я его запускаю, но триггер на самом деле тоже ничего не делает - number_of_beers_produced равен нулю для каждой пивоварни, независимо от того, сколько их пива находится в базе данных.

Есть личто-то действительно не так с тем, что я здесь делаю, или есть какой-то очевидный способ отладки этого? Я привык к IDE, где я могу шагать по коду и видеть, что происходит, я полагаю, что здесь нет никакого способа сделать это?

РЕДАКТИРОВАТЬ - БОЛЬШЕ ДЕТАЛЕЙ:

Таблицы создаются следующим образом:

create table beerStyleTable (
beer_style varchar(20) primary key,
country_of_origin varchar(13),
typical_IBU number,
typical_colour_EBC number,
typical_ABV number
);

create table breweryTable (
brewery varchar(20) primary key,
country varchar(13),
output_in_HL number,
year_founded number,
number_of_beers_produced number
);

create table beerTable (
beer_name varchar(24),
beer_style varchar(20),
brewery varchar(20),
IBU number,
Colour number,
ABV number,
PRIMARY KEY (beer_name, brewery),
FOREIGN KEY (beer_style) REFERENCES beerStyleTable(beer_style),
FOREIGN KEY (brewery) REFERENCES breweryTable(brewery)
);

Затем заполняется так:

insert into breweryTable values('Porterhouse', 'Ireland', 10000, 1989, 0);

insert into beerStyleTable values ('Irish Stout', 'Ireland', 35, 80, 4.5);

insert into beerTable values ('Oyster Stout', 'Irish Stout', 'Porterhouse', 45, 75, 5.2);

Затем запрос

SELECT * FROM breweryTable;

дает вывод

Porterhouse Ireland 10000 1989 0

Я задавался вопросом о том, чтобы дать начальное значение 0 для number_of_beers_produced, но дать его как NULL тоже не работает (это просто означает, что я неполучить любой пвыделите это поле для указанного выше запроса выбора.

Спасибо за любую помощь, которую вы можете предложить!

Diarmuid

1 Ответ

4 голосов
/ 10 декабря 2011

Ваш триггер не обновляет breweryTable, потому что вы используете автономную транзакцию.

Когда вы вставляете пиво в beerTable, только пиво, которое вставило это пиво, может видеть это пиво, пока вы не COMMIT. При вставке, обновлении или удалении сеанс открывает транзакцию, которая закрывается, когда вы COMMIT или ROLLBACK. Триггер использует автономную транзакцию, которая отделена от транзакции вашего сеанса. Ни одна транзакция не может увидеть незафиксированные данные, измененные другой.

Вот пример с тремя сортами пива, которые я сделал. У меня есть две пивоварни, образно называемые brewery 1 и brewery 2:

SQL> insert into beerTable (beer_name, brewery) values ('Eeuurgh', 'brewery 1');

1 row created.

SQL> insert into beerTable (beer_name, brewery) values ('Nasty Nasty', 'brewery 2');

1 row created.

SQL> insert into beerTable (beer_name, brewery) values ('Who drinks this stuff?', 'brewery 2');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from breweryTable;

BREWERY                        NUMBER_OF_BEERS_PRODUCED
------------------------------ ------------------------
brewery 1                                             0
brewery 2                                             0

Триггер сработал три раза, по одному для каждого оператора INSERT, но, поскольку он выполнялся в автономной транзакции, он не мог видеть вводимые каналы, поэтому сообщал, что счетчик равен нулю.

С другой стороны, если мы фиксируем после каждой строки, мы получаем следующий результат:

SQL> truncate table beerTable;

Table truncated.

SQL> insert into beerTable (beer_name, brewery) values ('Eeuurgh', 'brewery 1');

1 row created.

SQL> commit;

Commit complete.

SQL> insert into beerTable (beer_name, brewery) values ('Nasty Nasty', 'brewery 2');

1 row created.

SQL> commit;

Commit complete.

SQL> insert into beerTable (beer_name, brewery) values ('Who drinks this stuff?', 'brewery 2');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from breweryTable;

BREWERY                        NUMBER_OF_BEERS_PRODUCED
------------------------------ ------------------------
brewery 1                                             0
brewery 2                                             1

В этом случае, когда курок срабатывал в третий раз, он мог видеть пиво Nasty Nasty, сваренное на brewery 2, так как к тому времени это пиво было совершено. Тем не менее, он не мог видеть пиво Who drinks this stuff?, потому что это пиво еще не было совершено. Следовательно, счет для brewery 2 равен 1.

Как вы заметили, удаление автономной транзакции не сработало: вместо этого вы получили ошибку ORA-04091 «таблица мутирует».

Я должен спросить, почему вы хотите обновлять эти показатели следующим образом. Будете ли вы использовать их достаточно часто, чтобы сделать их актуальными на ходу?

РЕДАКТИРОВАТЬ : Я не могу вспомнить ситуацию, в которой было бы полезно обновлять эти показатели. Для поддержания их актуальности требуется немало усилий (вам нужно написать триггеры для обработки INSERT, UPDATE и DELETE), а также могут возникнуть проблемы с производительностью, если вы запускаете UPDATE или DELETE, которые влияют на многие из них. строк.

Альтернативный подход, который мог бы избежать ошибок таблицы мутаций, заключался бы в увеличении или уменьшении количества затронутых пивоваренных заводов в триггере. Однако эти показатели могут быть не синхронизированы с тем, что на самом деле находится в таблице, и я не уверен, что это также полностью устранит проблемы с производительностью.

Отслеживание этих показателей таким образом, в конечном счете, доставляет больше хлопот, чем стоит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...