November 2019

S M T W T F S
      12
34 5 678 9
10111213141516
17181920212223
24252627282930

Style Credit

Expand Cut Tags

No cut tags
Wednesday, October 5th, 2005 05:37 pm
А в этом оракле можно сделать триггер на UPDATE записи, который бы изменял поле в этой же самой записи?
Нормальным способом вложенный UPDATE из триггера не работает, получается deadlock. Autonomous transaction не помогает.

Это вообще возможно? Если да, то как? Если нет, то как это обойти?
В MSSQL оно замечательно работало.

Upd: уточненная задача выглядит так: в таблице есть вычисляемое поле, значение которого зависит от других полей _этой же записи_. Хочется возложить задачу вычисления этого поля на сервер путем триггера, срабатывающего на UPDATE. Так бывает?
Tags:
Wednesday, October 5th, 2005 04:54 pm (UTC)
Ты уж тогда полностью уточняй условия задачи... То, что ты написал сейчас - практически не имеет смысла: если у тебя уже есть вызов UPDATE - то что мешает изменить его так, чтобы одновременно апдейтилось не одно поле в записи, а два, три...? Это если рассматривать задачу именно так, как ты описал.

А я так понимаю, что это тот вопрос, который ты задавал вчера по аське? Если так - то там есть существенное уточнение: второй апдейт проводится по результатам функции, работающей на изменяемой в данный момент таблице. То есть - мутация, сразу и обязательно. И красивого универсального способа это обойти - я, честно говоря, за сутки так и не придумал.
Wednesday, October 5th, 2005 05:04 pm (UTC)
Не, вчерашний вопрос как раз решился автономными транзакциями.
Там изнутри апдейта вызывался селект, если этот селект завернуть в автономную транзакцию, то всё хорошо.
А здесь накладываются два апдейта, так уже не обойдешь.

Задача такая: есть поле, значение которого зависит от двух других полей в этой же записи (на самом деле, оно еще может зависеть от других записей, но это уже не актуально, см. выше).
Хочется задачу вычисления этого поля возложить на сервер, а не на клиента. Чтоб при изменении одного из тех двух полей третье вычислялось само. Иначе нафига вообще нужны триггеры?
Wednesday, October 5th, 2005 05:06 pm (UTC)
Решиться должно двумя триггерами, если допускает логика. Первый срабатывает на BEFORE UPDATE и вычисляет первые два поля. Второй - AFTER UPDATE: он дает тебе третье поле. Кажется, так дедлоков можно избежать.
Wednesday, October 5th, 2005 05:11 pm (UTC)
Не, вычислить надо всего одно поле, а значения тех двух, от которых оно зависит, могут изменяться пользователем.

Проблема в том, что если я изнутри триггера, повешенного на апдейт, вызываю апдейт этой же записи, то наступает deadlock.
Если из триггера вызывать апдейт других записей в этой же таблице, то все нормально, я пробовал, а вот на текущую - никак не получается :(
Wednesday, October 5th, 2005 05:16 pm (UTC)
Дык и не должно!
Ну сам посуди: ты апдейтишь запись (Оракл ее, естественно, блокирует с началом транзакции), срабатывает триггер, в котором та же запись опять апдейтится... вызывая повторное срабатывание триггера на апдейт! Ну, и как, спрашивается, Оракл должен разблокировать запись в условиях бесконечного вызова одного и того же триггера?! А никак. Вот тебе и deadlock, вполне законный.
Wednesday, October 5th, 2005 05:20 pm (UTC)
Это понятно. А что делать? В смысле, можно ли вообще в оракле реализовать автоматическое вычисление поля триггером по изменению других полей в записи?
Wednesday, October 5th, 2005 05:54 pm (UTC)
а не нарушаются ли тут 3 и 4 НФ? :)
Wednesday, October 5th, 2005 06:09 pm (UTC)
Да, нарушаются. Но задача такая. Вычисление этого значения - процедура трудоемкая, и выполнять ее при каждом запросе к таблице крайне расточительно. Надо один раз посчитать при изменении записи.
Wednesday, October 5th, 2005 05:53 pm (UTC)
вроде как при триггере before update там есть набор значений in и набор значений out, и этот out можно менять.
Wednesday, October 5th, 2005 05:57 pm (UTC)
В смысле - in и out? Триггер может вообще ничего не принимать и ничего не возвращать - это же не функция...
Или имеется в виду список полей, при изменении которых срабатывает триггер? Если так, то именно туда [livejournal.com profile] dil и копает как раз сейчас :). Ибо логика схемы там такая, что застрелиться можно :).
Wednesday, October 5th, 2005 06:01 pm (UTC)


CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE
ON orders
FOR EACH ROW

DECLARE
v_username varchar2(10);

BEGIN

-- Find username of person performing UPDATE on the table
SELECT user INTO v_username
FROM dual;

-- Update updated_date field to current system date
:new.updated_date := sysdate;

-- Update updated_by field to the username of the person performing the UPDATE
:new.updated_by := v_username;

END;
Wednesday, October 5th, 2005 06:11 pm (UTC)
О, это, кажется, оно.
Спасибо, завтра буду проверять. А то уже поздно, с работы выгоняют ;)
Wednesday, October 5th, 2005 06:15 pm (UTC)
сударь, вы меня удивляете :)
jfui, оракл живьем я видел лет пять назад, а сейчас в гугле набрал
before update trigger oracle (http://www.google.ru/search?q=before+update+trigger+oracle&sourceid=mozilla-search&start=0&start=0&ie=utf-8&oe=utf-8&client=firefox&rls=org.mozilla:en-US:unofficial) и открыл вторую ссылку из результатов (http://www.techonthenet.com/oracle/triggers/before_update.php) :)
Thursday, October 6th, 2005 09:18 am (UTC)
(шепотом) а я его впервые увидел две недели назад. Мне его выдали, и сказали, что вот эта программа, которая раньше работала с вот этой базой на MSSQL, должна работать с этой же базой, но на оракле. Потому что заказчик так хочет. Причем, как всегда, уже вчера ;)
Wednesday, October 5th, 2005 06:33 pm (UTC)
Тьфу ты :). Ну конечно же - использование :new и :old!
Вот что значит давно уже переквалифицироваться в управдомы перестать заниматься разработкой и уйти в админоиды... :))
Thursday, October 6th, 2005 04:46 pm (UTC)
Вах! Работает, спасибо. Пойду приделывать то же ссамое на insert, а то оно что-то не работает