powered by simpleCommunicator - 2.0.50     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Строковый триггер от мутирования
25 сообщений из 27, страница 1 из 2
Строковый триггер от мутирования
    #40068677
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ребята, нужна ваша помощь!

Необходимо обойти проблему мутирующей таблицы “mutating table”.

Имеются таблицы: Employees (где содержатся сведения о сотрудниках, в частности идентификатор должности и зарплата) и Jobs (где содержатся сведения о должностях, в частности идентификатор должности и минимальная зарплата).

Необходимо создать строчный ( не составной ) триггер, который связан с Jobs, который будет вызывать процедуру upd_sal(job_id, salary), если обновится минимальный уровень зарплаты для должности.

Варианты ниже не работают:
1)
Код: plsql
1.
2.
3.
4.
5.
6.
7.
CREATE OR REPLACE TRIGGER trg
AFTER UPDATE OF min_sal ON jobs
FOR EACH ROW
WHEN (OLD.min_sal != NEW.min_sal)
BEGIN
    upd_sal(:NEW.job_id, :NEW.min_sal);
END;


2)
Код: plsql
1.
2.
3.
4.
5.
6.
CREATE OR REPLACE TRIGGER trg
BEFORE UPDATE OF min_sal ON jobs
FOR EACH ROW
BEGIN
    upd_sal(:NEW.job_id, :NEW.min_sal);
END;



Я никак не пойму, как создать такой триггер.
Помогите, пожалуйста!
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068702
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stravicki,

Триггер надо создавать на Employees

зы
покажите upd_sal

.....
stax
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068710
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Требуется создать триггер именно на Jobs.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
PROCEDURE upd_sal(
    jobid IN employees.job_id%TYPE,
    sal IN employees.salary%TYPE)
IS
TYPE t_emp IS TABLE OF employees.employee_id%TYPE;
tab_empid t_emp;
BEGIN
    SELECT employee_id
    BULK COLLECT INTO tab_empid 
    FROM employees
    WHERE job_id = jobid AND salary < sal;
    
    FORALL empid IN tab_empid.FIRST..tab_empid.LAST
        UPDATE employees
        SET salary = sal
        WHERE employee_id = tab_empid(empid);
END;
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068726
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stravicki
Stax,

Требуется создать триггер именно на Jobs.



я не так понял

тоесть, в Employees не должно быть сотрудников с ЗП меньше min_sal?

не могу придумать где там мутация

зы
я так понимаю ФК с Employees на Jobs

.....
stax
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068729
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax ,

автортоесть, в Employees не должно быть сотрудников с ЗП меньше min_sal?
Да, верно.

авторя так понимаю ФК с Employees на Jobs
Да.

авторне могу придумать где там мутация
К таблице Employees есть свой триггер check_salary, который читает Jobs. Плюс, есть check_salary, созданный собственноручно.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068740
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stravicki

К таблице Employees есть свой триггер check_salary, который читает Jobs. Плюс, есть check_salary, созданный собственноручно.


тогда обычный обход мутации https://www.sql.ru/faq/faq_topic.aspx?fid=513

в FOR EACH ROW накапливаете данные, в операторном after меняете ЗП

зы
компаудный я так понял нельзя пользовать

pss
саму процедуру upd_sal пока не рассматриваем
.....
stax
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068743
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Важным условием является отсутствие введения дополнительных триггеров.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068745
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С помощью Dynamic SQL сначала деактивируешь триггер на Jobs, потом делаешь update, потом
активируешь его обратно.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068757
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry Sibiryakov,

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

Код: plsql
1.
2.
3.
4.
5.
CREATE OR REPLACE TRIGGER emp_initjobs_trg 
BEFORE INSERT OR UPDATE ON employees
BEGIN
    jobs_pkg.initialize;
END;



и

Код: plsql
1.
2.
3.
4.
5.
CREATE OR REPLACE TRIGGER init_jobspkg_trg
BEFORE INSERT OR UPDATE ON jobs
BEGIN
  jobs_pkg.initialize;
END;



Верно ли понимаю, что надо применить инструкцию
Код: plsql
1.
EXECUTE IMMEDIATE 'ALTER TRIGGER trg DISABLE'

до инициализации и включить триггер после update?

Возможно, проблема в том, что инициализация вызывается дважды.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068759
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Там у тебя ещё и пакеты? Суровый зоопарк. Тогда отключать не надо, достаточно в нём
проверять флаг-пакетную переменную.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068764
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry Sibiryakov,

автордостаточно в нём проверять флаг-пакетную переменную
Не совсем понимаю, что это. Например, переменная в пакете типа Boolean?

Тогда получается надо изменять флаг в init_jobspkg_trg дважды: до и после update. И этот триггер будет составной, либо его можно разбить на два statement-триггера.
Есть какие-то варианты, чтобы этот триггер оставался before insert or update statement-триггером?
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068787
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stravicki,

Задачу "фтопку". Предположим есть идентификатор должности X с минимальной зарплатой $40,000 в год. И два работника с идентификатором должности X - Вася и Петя. Вася потолковей и его зарплата $45,000 в год. А Петя так себе и его зарплата минимальная $40,000 в год. Теперь пришло ц.у. минимальная зарплата для должности X $45,000 в год. И что теперь? Вася и Петя будут получать одинаково? Так Вася тут-же уйдет. Вообще-то все вопросы зарплаты решаются сугубо индивидуально даже при увеличении минимальной зарплаты ибо хоть и не напрямую это касается всех работников и начальство должно решить а поднять ли Васе зарплату или пусть уходит если не нравится. Второе: как часто меняется минимальная зарплата что это надо автоматизировать да еще через триггер? Третье: даже если "начальство приказало", то "строчный (не составной) триггер" не есть business requirement а есть "создам себе трудности и успешно их преодолею любой ценой".

Вообщем дерзай.

SY.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068793
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SYТак Вася тут-же уйдет.

Куда он из учебной схемы HR уйдёт-то? В схему scott или sys?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068836
Правильный Вася
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как партизан на допросе, всё клещами тянуть надо.
Изложи ситуацию ПОЛНОСТЬЮ:
1. всё, что есть,
2. всё, что надо
3. почему надо именно так, а не как-то иначе.
Утайка информации приравнивается к отсутствию заинтересованности в результате, что влечёт безразличие со стороны отвечающих.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068849
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Правильный Вася
Как партизан на допросе,

ето явно не лабораторка, уж больно красиво оформлено

скорее всего, часть логики из пакета решили перенести в триггер, и нарвались на мутацию

....
stax
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068875
delphinotes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Мутация - это, в некотором роде, циклическая зависимость. Для ухода от циклических зависимостей, код разбивается на слои: это когда код верхнего уровня может вызвать код нижнего, но не наоборот.

Вариант обхода по ссылке выше - наименее трудозатратный и вполне приемлем в простых случаях.

Для упрощения кода в сложных ситуациях (чтобы легче понимать, что происходит), можно применять вариант, когда таблицы оборачиваются вьюхами, и клиенсткий код работает не с таблицами, а именно с вьюхами - во вьюхах можно добавлять и фильтры, и instead-of триггеры.

В уже существующей инфраструктуре я такой вариант применял:
а) исходные таблицы переименовываются (либо вообще выносятся в отдельную схему)
б) создаются вьюхи, имена которых совпадают с предыдущими именами таблиц
в) на вьюхах пишутся instead-of триггеры
г) ну и гранты (с таблиц убрать, отдать вьюхам).
В итоге весь клиентский код, который работал с таблицами, теперь работает с представлениями и его менять не нужно. А со стороны БД код разделился на два слоя, его легче поддерживать, плюс появляется простой способ обхода триггеров на вью - это прямая запись в таблицы (без объявления и переключения туда/сюда всяких флагов).

Но это надо знать, как там клиентский код с таблицами работает, может он анализирует оракловый словарь на предмет индексов/констрейнтов и т.п. (что маловероятно).
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068908
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть строчный (не составной) AFTER UPDATE триггер на Jobs, который срабатывает после обновления минимальной з/п в Jobs. В этом триггере вызывается процедура на обновление з/п в таблице Employees. Также есть BEFORE триггер (1) для инициализации локальной индексированной таблицы - копии Jobs (процедура инициализации разработана в пакете).

На таблицу Employees есть триггер check_salary, в котором вызывается процедура для проверки соответствия з/п диапазону [min_sal;max_sal]. При этом также есть BEFORE триггер (2), вызывающий процедуру инициализации локальной индексированной таблицы для Jobs.

Возникает мутация, которая, как я понимаю, связана с тем, что идет обращение к индексированной таблице одновременно и со стороны триггера на Jobs, и со стороны триггера на Employees (но почему?).

Для решения этой проблемы я использую булевскую переменную в том самом пакете, где и процедура инициализации. Значение флага устанавливаю в триггере (1), а потом сбрасываю. В триггере (2) проверяю, что он сброшен. При этом, триггер на Jobs приходится переделать из statement BEFORE INSERT OR UPDATE в составной (добавляю раздел AFTER, где сбрасываю значение булевской переменной). Как-то можно избежать этого составного триггера (желательно без добавления новых объектов в БД)?
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068931
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stravicki

Возникает мутация, которая, как я понимаю, связана с тем, что идет обращение к индексированной таблице одновременно и со стороны триггера на Jobs, и со стороны триггера на Employees (но почему?).


нет

"закоментируйте" обращение к jobs из check_salary, и мутация "пропадет"

.....
stax
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068934
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

В check_salary идет обращение не к самой таблице Jobs, а к индексированной таблице.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068939
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stravicki
Stax,

В check_salary идет обращение не к самой таблице Jobs, а к индексированной таблице.

что такое индексированная таблица?

покажите полностью текст ошибки мутации

.....
stax
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068940
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Неужели так сложно выяснить на каком именно операторе возникает ошибка мутации и call
stack к нему?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068954
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
drop table emp_table purge
/
drop table job_table purge
/
create table job_table(
                       job_id number,
                       min_salary number
                      )
/
alter table job_table
  add constraint job_table_pk
    primary key(job_id)
/
create table emp_table(
                       employee_id number,
                       name varchar2(10),
                       job_id number,
                       salary number
                      )
/
alter table emp_table
  add constraint emp_table_pk
    primary key(employee_id)
/
alter table emp_table
  add constraint emp_table_fk1
    foreign key(job_id)
    references job_table
/
create or replace
  trigger job_table_bur
    before update
    on job_table
    for each row
    begin
        if :old.min_salary != :new.min_salary or :old.job_id != :new.job_id
          then
            update emp_table
               set salary = greatest(salary,:new.min_salary),
                   job_id = :new.job_id
             where job_id = :old.job_id;
        end if;
end;
/
insert
  into job_table
  values(
         1,
         30000
        )
/
insert
  into job_table
  values(
         2,
         40000
        )
/
insert
  into emp_table
  values(
         1,
         'Vasya',
         1,
         30000
        )
/
insert
  into emp_table
  values(
         2,
         'Petya',
         1,
         30000
        )
/
insert
  into emp_table
  values(
         3,
         'Misha',
         1,
         40000
        )
/
insert
  into emp_table
  values(
         4,
         'Sasha',
         2,
         40000
        )
/
insert
  into emp_table
  values(
         5,
         'Masha',
         2,
         40000
        )
/
insert
  into emp_table
  values(
         6,
         'Dasha',
         2,
         45000
        )
/
commit
/

Commit complete.

SQL> select  *
  2    from  emp_table
  3  /

EMPLOYEE_ID NAME           JOB_ID     SALARY
----------- ---------- ---------- ----------
          1 Vasya               1      30000
          2 Petya               1      30000
          3 Misha               1      40000
          4 Sasha               2      40000
          5 Masha               2      40000
          6 Dasha               2      45000

6 rows selected.

SQL> select  *
  2    from  job_table
  3  /

    JOB_ID MIN_SALARY
---------- ----------
         1      30000
         2      40000

SQL> update job_table
  2     set min_salary = min_salary + 5000,
  3         job_id = job_id + 10
  4  /

2 rows updated.

SQL> select  *
  2    from  emp_table
  3  /

EMPLOYEE_ID NAME           JOB_ID     SALARY
----------- ---------- ---------- ----------
          1 Vasya              11      35000
          2 Petya              11      35000
          3 Misha              11      40000
          4 Sasha              12      45000
          5 Masha              12      45000
          6 Dasha              12      45000

6 rows selected.

SQL> select  *
  2    from  job_table
  3  /

    JOB_ID MIN_SALARY
---------- ----------
        11      35000
        12      45000

SQL>



SY.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40068959
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY,

Stravicki

К таблице Employees есть свой триггер check_salary, который читает Jobs . Плюс, есть check_salary, созданный собственноручно.



ps
salary = greatest(salary,:new.min_salary) не луче ли вынести во where salary> :new.min_salary?
.....
stax
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40069002
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax
SY,


salary = greatest(salary,:new.min_salary) не луче ли вынести во where salary> :new.min_salary?
.....
stax


Мой пример показывает триггер работает даже если JOB_ID натуральный а не суррогатный ключ и посему учитывает ситуацию когда было изменение MIN_SALARY и/или JOB_ID. Так-что where salary > :new.min_salary не катит. При толковом нормализованном дизайне когда JOB_ID суррогатный ключ, да - greatest не нужен и триггер выглядит так:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
create or replace
  trigger job_table_bur
    before update
    on job_table
    for each row
    begin
        if :old.min_salary != :new.min_salary
          then
            update emp_table
               set salary = :new.min_salary
             where job_id = :new.job_id
               and salary < :new.min_salary;
        end if;
end;
/



SY.
...
Рейтинг: 0 / 0
Строковый триггер от мутирования
    #40069041
Stravicki
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
К сожалению, это не совсем то, что требуется.

Мне бы понять, можно ли как-то при использовании пакетной флаговой переменной обойти использование составного триггера с сохранением всех требуемых типов триггеров.
...
Рейтинг: 0 / 0
25 сообщений из 27, страница 1 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Строковый триггер от мутирования
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]