powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как создать "замещающий триггер"&
17 сообщений из 17, страница 1 из 1
Как создать "замещающий триггер"&
    #38537349
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день. Есть задача создать полноценный версионный справочник. То есть есть поля с кодами объектов и датами начала действия и конца действия. При добавлении, обновлении и удалении ничего удаляется и не модифицируется, а только добавляется и обновляется дата диапазонов действия.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
create table spr_tem
(
  id bigint NOT NULL DEFAULT nextval(('id_spr_tem_seq'::text)::regclass),
  code bigint,
  name text,
  date_begin timestamp default now(),
  date_end timestamp default '2999-12-31',  
  id_parent bigint, 
  CONSTRAINT pk_spr_tem PRIMARY KEY (id)
);


С триггером на добавление все понятно, он генерирует код объекта, если его нет (реальное создание)
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE OR REPLACE FUNCTION tg_spr_tem_before_ins()
  RETURNS trigger AS
$BODY$ --обновляем код
begin 
  raise notice 'ins';
  if new.code is null then new.code = new.id;end if;
  return new;
end;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
DROP TRIGGER if exists tg_spr_tem_ins ON spr_tem;
CREATE TRIGGER tg_spr_tem_ins BEFORE INSERT ON spr_tem FOR EACH ROW EXECUTE PROCEDURE tg_spr_tem_before_ins();  



А вот что написать в upd и del - не знаю. Я пытаюсь модифицировать строки old и new, но сервер их все равно удаляет. Может, есть какие хитрые опции создания триггера? По сути, нужен триггер, которые меняет команды upd и del на (ins,upd) и (upd) соответсвенно. В MS SQL такая примочка была, а в PG не нашел :(

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
CREATE OR REPLACE FUNCTION tg_spr_tem_before_upd()
  RETURNS trigger AS
$BODY$
begin --помечаем как удаленую
  raise notice 'upd';
  if new.code = old.code then old.date_end = new.date_begin;end if;
  return new;
end;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
DROP TRIGGER if exists tg_spr_tem_upd ON spr_tem;
CREATE TRIGGER tg_spr_tem_upd INSTEAD OF BEFORE spr_tem FOR EACH ROW EXECUTE PROCEDURE tg_spr_tem_before_upd();

CREATE OR REPLACE FUNCTION tg_spr_tem_before_del()
  RETURNS trigger AS
$BODY$
begin --помечаем как удаленую
  raise notice 'del';
  old.date_end = now();
  return old;
end;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
DROP TRIGGER if exists tg_spr_tem_del ON spr_tem;
CREATE TRIGGER tg_spr_tem_del BEFORE DELETE ON spr_tem FOR EACH ROW EXECUTE PROCEDURE tg_spr_tem_before_del(); 
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537354
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Естественно, вариант INSTEAD OF возможен, но он для вьюхи, а ее не хочется делать, так как это явный костыль будет
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537373
Фотография Ёш
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakamaЯ пытаюсь модифицировать строки old и new, но сервер их все равно удаляет. Может, есть какие хитрые опции создания триггера?А почему Вы документацию не читает на СУБД которую программируете? Там же всё написано: http://www.postgresql.org/docs/9.3/static/plpgsql-trigger.html
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537375
Фотография Ёш
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakama,

авторRow-level triggers fired BEFORE can return null to signal the trigger manager to skip the rest of the operation for this row (i.e., subsequent triggers are not fired, and the INSERT/UPDATE/DELETE does not occur for this row).
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537379
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ёш,

Читал я это. Но толку? Допустим, для update. Присваиваю я old = null, а дату ,которую я исправил в ней, куда девать? Или нужно править не в old, а в самой таблице? Аналогично, с del?
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537383
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
И потом, допустим, что для upd разобрались. А добавление - вручную прописывать Insert? Просто у меня таблиц много, хотелось бы автоматизировать это хозяйство с точки зрения написания
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537386
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
kamakama,

Код: 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.
CREATE OR REPLACE FUNCTION tg_spr_tem_before_upd()
  RETURNS trigger AS
$BODY$
begin --помечаем как удаленую
  raise notice 'upd';
  update spr_tem set date_end = new.date_begin where spr_tem.id = old.id;
  insert into spr_tem (code,name) values (new.code,new.name);
  old = null;
  new = null;
  return new;
end;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
DROP TRIGGER if exists tg_spr_tem_upd ON spr_tem;
CREATE TRIGGER tg_spr_tem_upd BEFORE UPDATE OF name ON spr_tem FOR EACH ROW EXECUTE PROCEDURE tg_spr_tem_before_upd();  

CREATE OR REPLACE FUNCTION tg_spr_tem_before_del()
  RETURNS trigger AS
$BODY$
begin --помечаем как удаленую
  raise notice 'del';
  update spr_tem set date_end = now() where spr_tem.id = old.id;
  return null;
end;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
DROP TRIGGER if exists tg_spr_tem_del ON spr_tem;
CREATE TRIGGER tg_spr_tem_del BEFORE DELETE ON spr_tem FOR EACH ROW EXECUTE PROCEDURE tg_spr_tem_before_del(); 



Получилось что-то типа такого. Но
1) Нужно в 2 х местах явно указывать колонки в upd, что бы не было рекурсии. А это плохо
2) Быстродействие такой схемы весьма сомнительно.
Может быть, есть другие какие способы?
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537436
Sergei.Agalakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чем не устраивает иметь две таблицы: активные данные и историю изменений?
Example 40-4. A PL/pgSQL Trigger Procedure For Auditing
Это многие проходили. Не так уж часто нужна история изменений, чаще работают с текущими версиями.
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537562
Павел Лузанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakamaЕстественно, вариант INSTEAD OF возможен, но он для вьюхи, а ее не хочется делать, так как это явный костыль будет

Костылей не увидел.
Триггера instead of для этой задачи идеально подходят.
При этом пользователи должны работать только с view.
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537563
Павел Лузанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakama... Просто у меня таблиц много, хотелось бы автоматизировать это хозяйство с точки зрения написания

Для автоматизации можно написать скрипт, которому на вход подается имя таблицы/view, а на выходе получается текст функций/триггеров.
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537567
Павел Лузанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakamaПолучилось что-то типа такого. Но
1) Нужно в 2 х местах явно указывать колонки в upd, что бы не было рекурсии. А это плохо
2) Быстродействие такой схемы весьма сомнительно.
Может быть, есть другие какие способы?

Про быстродействие.
Речь же идет о справочнике.
Для справочников операции изменения обычно не столь часты, чтобы говорить о проблемах быстродействия.

Скорее нужно говорить о скорости выборки (select) из таблицы, в которой полная история изменений ведется.
И со временем количество действующих (актуальных) строк будет заметно меньше чем строк с историей изменений.
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537949
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Павел Лузанов,

Про редкость изменения согласен. Разбить на несколько таблиц - тоже вариант, его пока не рассматривал. У меня есть еще заковырка - диапазон дат действия для меня не совпадают с часами системы. Ну то есть при добавлении записи я могу насильно указать период действия (например, законого акта), который не совпадает с моменттом создания записи. Тонкость момента связана с тем, что я пытался использовать 2 таких конструкции, получилось плохо
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
CREATE OR REPLACE FUNCTION tg_spr_tem_before_upd()
  RETURNS trigger AS
$BODY$
begin --помечаем как удаленую
  raise notice 'upd';
  --update spr_tem set date_end = now()/*new.date_begin*/ where spr_tem.id = old.id;
  --insert into spr_tem (code,name,date_begin) values (new.code,new.name,now());
  update spr_tem set date_end = new.date_begin where spr_tem.id = old.id;
  insert into spr_tem (code,name,date_begin) values (new.code,new.name,new.date_begin);  
  return null;
end;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
DROP TRIGGER if exists tg_spr_tem_upd ON spr_tem;
CREATE TRIGGER tg_spr_tem_upd BEFORE UPDATE OF name ON spr_tem FOR EACH ROW EXECUTE PROCEDURE tg_spr_tem_before_upd();  


Функция работает криво. Почему то при связке
Код: plsql
1.
2.
insert into spr_tem (name) values ('D');
update spr_tem set name = 'F' where name = 'E'


получается вот что
22;19;"E";"";;"2014-01-25 23:04:19.045";"2014-01-25 23:04:19.045";
23;19;"F";"";;"2014-01-25 23:04:19.045";"2999-12-31 00:00:00";
То есть даты плывут, они все одинаковые
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537952
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Виноват, конечно, же добавляля не D, а E
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38537995
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sergei.AgalakovЧем не устраивает иметь две таблицы: активные данные и историю изменений?
Example 40-4. A PL/pgSQL Trigger Procedure For Auditing
Это многие проходили. Не так уж часто нужна история изменений, чаще работают с текущими версиями.

Мешают оставшиеся ссылки в других таблицах на "старые записи")
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38538136
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не настолько. Ссылки обычно в таких случаюх дают не по ключу, а по коду и дате действия записи. По правилу формирования таблицы это сочетание будет уникальным и вполне пригодно вкачестве составного ключа. А быстродействие - расплата за универсальность.
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38539632
Sergei.Agalakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Собственно все зависит от того, насколько часто обновляются справочные данные. Если редко, то одной таблицей проще обойтись, а если они обновляются часто, то лучше таблицы разбить на две: актуальные и архивные записи. Иначе в одной таблице скоро на одну полезную запись будет несколько устаревших, которые бизнес логикой игнорируются, но память мсправно кушают.
...
Рейтинг: 0 / 0
Как создать "замещающий триггер"&
    #38539693
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakamaПавел Лузанов,

Про редкость изменения согласен. Разбить на несколько таблиц - тоже вариант, его пока не рассматривал. У меня есть еще заковырка - диапазон дат действия для меня не совпадают с часами системы. Ну то есть при добавлении записи я могу насильно указать период действия (например, законого акта), который не совпадает с моменттом создания записи.
Не мешай в одну кучу, бизнес-даты и даты системные!!!
Выбери что-нибудь одно! И только одно!!! В смысле версионность обязательно надо вести в рамках одного типа дат!
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как создать "замещающий триггер"&
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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