Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Сравнение СУБД Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
Предлагаю обменяться мнениями относительно поддержки триггеров в разных СУБД.
SQL Server - instead-of и after. Вспыхивают на операцию, а не на отдельную запись. After - вешаются только на таблицы, может быть много на каждую операцию, есть возможность задать, кто будет стрелять первым, кто последним. Instead-of - вешаются на таблицы и представления, по одному на каждую операцию, традиционно используются для задания ссылочной целостности, более сложной нежели декларативная, и для создания обновляемых вьюх, классически не являющихся таковыми.
Before-триггеров нет. (Буду признателен за примеры их полезности).
7 апр 03, 13:23    [166498]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
DimaR
Member

Откуда:
Сообщений: 1570
У меня знаний не так моно но попробую вкратце расказать про Oracle

Есть тригеры:
BEFORE, AFTER, INSTEAD OF
dml_event: Это операции с данными: DELETE INSERT UPDATE
может быть для каждой строки или для оператора.

ddl_event: Это операции над структурой базы типа ALTER, RENAME, GRANT ...иеще много, т.е. изменение структуры таблиц, привелегии ит.д
млжет быть на схему конкретного пользователя или базу.

database_event: это коннект-дисконнект пользователя, запуск-останов базы, ошибка сервера.

в качестве тела тригера используеться pl/sql блок,
ну и дополнительно (это не только в тригере) возиожность выполнения автономной транзакции, т.е. независимой от транзакции пользователя.
Если чего не так, или не дописал поправте.
7 апр 03, 13:58    [166561]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
Триггеров на DDL и сист.события типа connect/disconnect в SQL Server нет. По слухам, обещают в след.версии. Согласен, что это удобно.
7 апр 03, 14:13    [166589]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
nick
Member

Откуда: Москва
Сообщений: 129
"Before-триггеров нет. (Буду признателен за примеры их полезности)."
У нас есть поле которое генерится автоматически, но пользователь может исходя из каких-то своих соображений ввести свое значение, так вот в Before тригере я проверяю, если это поле null, то я генерю сам, иначе использую значение пользавателя.
Например это используется при генерации латинского написания русского имени.
7 апр 03, 14:43    [166647]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Roman Ignatiev
Member

Откуда: Москва
Сообщений: 680
IB/FB
Есть триггеры before и after действия. Подключаются на таблицы и view, правда, view я не пользуюсь, поэтому ничего о них сказать особого не могу.
Триггеров на системные события как таковых нет, но при желании всегда можно сделать их на системные таблицы - по крайней мере на DDL отрабатывать будут. Честно говоря, не знаю, для чего это нужно.
Триггер отрабатывает для каждой записи, можно установить порядок их выполнения. Естественно, возможно несколько триггеров на одно действие, лишь бы имена различались.
По поводу применения триггеров before - у меня такие же непонятки насчет применения instead-of. А в before обычно выполняют следующие действия:
1. Заполнение дополнительных полей данными, например, автоинкремент или преобразование значения поля в верхний регистр и тд. Вычислимые поля хотя и есть, но не индексируются, поэтому часто удобно просто создать служебное поле, заполнить его значением другого в верхнем регистре - и готов case insensitive поиск по индексу.
2. Дополнительная проверка ссылочной целостности - foreign key и check отрабатывает между триггерами before & after, но выдает не слишком читабельные сообщения, поэтому удобно проверить в before и выдать исключение вида "А вот так делать нельзя" - в случае исключения дальше не идет и транзакция откатывается

Насчет остального - в триггере before запись в таблице еще не изменена (не вставлена/не удалена), в after - уже сделано. В триггере доступны префиксы OLD & NEW - там, где имеют смысл, соответственно, старое и новое значение поля. Присвоение значения переменным NEW.<FieldName> и тд не вызывает, естественно, новой отработки триггера.

Имхо, наиболее часто встречается триггер вида
create trigger ....
before insert
as
begin
if (NEW.MyField is NULL) then
NEW.MyField = Gen_ID(MyGenerator,1);
end

Удобно - автоинкремент, но отрабатывает только если клиент не задал значения поля.
7 апр 03, 14:53    [166660]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
2nick

Почему эту проверку нельзя сделать при помощи after-триггера?

if exists(select 1 from information_schema.tables where table_name = 't' and table_type = 'BASE TABLE') drop table t
create table t (id int identity primary key, fld nvarchar(10))

if objectproperty(object_id('tr1'), 'ExecIsAfterTrigger') = 1 drop trigger tr1
go
create trigger tr1 on t after insert as
update t set fld = 'Пусто' from t inner join inserted i on t.id = i.id where i.fld is null
go

insert t (fld) values (null)

select * from t

id fld
----------- ----------
1 Пусто

(1 row(s) affected)
7 апр 03, 15:08    [166689]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
AI
Member

Откуда: Москва
Сообщений: 2817
2 Дед Маздай.

Потому что как-то неаккуратненько так делать...

Немного уточню по оракулу. instead of триггеры вешаются только на вьюшки. И в теле триггера можно вызывать процедуры PL/SQL & java.
7 апр 03, 15:17    [166705]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
nick
Member

Откуда: Москва
Сообщений: 129
2Дед Маздай
Я привел лишь пример.
1.Как минимум потому что твой вариант длинее.(Зачем делать инсерт, а потом апдейт,если все можно сделать в одном инсерте???)
2.Если нужно будет вставлять много записей, то твой вариант будет работать очень медленно.
Все можно сделать, как правило, несколькими методами. Можно вообще не использавать тригеры.
7 апр 03, 15:21    [166713]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Crip
Member

Откуда:
Сообщений: 2490
>Если нужно будет вставлять много записей, то твой вариант будет работать очень медленно.

Да ну ... Насколько я понимаю на id весит кластерный индекс...Все пройдет быстро
7 апр 03, 15:43    [166749]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
nick
Member

Откуда: Москва
Сообщений: 129
А кстати, что у любой таблицы должен быть primary key???
А если его нет?
7 апр 03, 15:46    [166753]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
2Al
Почему неаккуратненько?

2nick
Если нужно вставлять много записей (insert ... select), то мне кажется, мой вариант будет быстрее, потому что он срабатывает сразу для всех вставляемых записей, а не идет по каждой, как курсор.

На самом деле Вы и Roman Ignatiev навели меня на пример, когда, по-видимому, без before-триггера не обойтись. Я имею в виду не саму генерацию автоинкремента, которая решается с помощью identity (SQL Server) или sequence (Oracle), а вставку null в поле not null. Instead-of триггер (по крайней мере в SQL Server) срабатывает раньше любых констрейнтов, кроме not null и identity.
7 апр 03, 15:56    [166764]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Roman Ignatiev
Member

Откуда: Москва
Сообщений: 680
Насчет вставки NULL в поле not NULL - немного не понял...
Имеется в виду проверка - если значение NULL, то присвоить что-то?
Дело в том, что если поле not NULL и содержит NULL - в IB это никак не пройдет - проверка сработает.
7 апр 03, 16:08    [166785]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 32174
Да, для генерации ключей или что-то вроде своего инкрементного поля это было-бы полезно. А в ИБ текст типа
create trigger ....
before insert
as
begin
if (NEW.MyField is NULL) then
NEW.MyField = Gen_ID(MyGenerator,1);
end
получается, не будет работать, если MyField - ПК?

А можно спросить знатоков - в Oracle можно работать со всеми изменёнными записями, т.е. есть-ли там таблицы типа inserted/deleted?
7 апр 03, 16:40    [166842]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
2Roman Ignatiev

Да, я имел в виду, что проверка not null срабатывает раньше instead-of триггера. Т.е. если
create table t (id int identity primary key, fld char(3) not null)
create trigger tr1 on t instead of insert as
insert t (fld) select coalesce(fld, 'Пусто') from inserted
то
insert t (fld) values (null) не пройдет.

Для всех остальных констрейнтов instead-of триггер срабатывает раньше. Напр.
create table t (id int identity primary key, fld varchar(3) check (fld like '[0-9][0-9][0-9]'))
create trigger tr1 on t instead of insert as
insert t (fld) select case when fld like '[0-9][0-9][0-9]' then fld else '000' end from inserted
insert t (fld) values (1) - вмешивается триггер, вставляет '000'.
7 апр 03, 16:49    [166861]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Roman Ignatiev
Member

Откуда: Москва
Сообщений: 680
Бррр... Понял - вставляешь Null и хочешь, чтобы в триггере подставилось значение по-умолчанию.
Да, типичная задача для before.
2alexeyvg
Будет он работать, проверка на not null в IB идет после before триггера (вообще все check, not null, foreign key и тд идут после), так что так и подставляется, и не важно, первичный ключ или нет.
И, кстати, наконец-то я понял как применять instead of - ручками вставляешь в таблицы. Удобно, когда, например, view не обновляемое. В IB нет такого :-( В before просто ставишь/уточняешь/проверяешь значения полей, потом запись вставляется в таблицу, делается проверка целостности и отрабатывают триггеры на after, в которых значения полей уже не поменяешь (ошибку, кстати, тоже не дает, просто игнорирует присвоение NEW).
7 апр 03, 17:09    [166896]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
>"Понял - вставляешь Null и хочешь, чтобы в триггере подставилось значение по-умолчанию"
Есть ли в IB возможность сделать default на поле декларативно, без before?
То же для автоинкремента?
7 апр 03, 17:28    [166932]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Roman Ignatiev
Member

Откуда: Москва
Сообщений: 680
Default - конечно можно, стандарт
А вот identity - такого нет, есть генераторы. И, на мой взгляд, это на порядок удобнее, чем identity.
Приведу пример: На клиенте - связка master-detail, что довольно типично, причем связь по полю с identity. Пользователь вставляет запись в мастера, и хочет вставить записи в detail... А чтобы получить значение поля связи, я должен послать запись на сервер и перечитать запись (хотя бы это поле). - неудобно. С IB - просто, можно дать select Gen_ID(<Generator>,1) from rdb$database - в этой таблице всегда одна запись. Я предпочитаю честно создать процедуру
create procedure MyTable_ID
returns (ID integer)
as
begin
ID = Gen_ID(MyTableGen,1);
end
для каждой таблицы с автоинкрементом, и присваивать значение полю на клиенте. В соединении с упомянутым триггером работает великолепно.
Ну и плюс - генераторы можно применять не только для автоинкремента :-)
7 апр 03, 17:41    [166956]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
Вдогонку: если в IB можно вешать before на view, то почему не сделать классически необновляемый view обновляемым при помощи before так же, как в SQL Srv это делается при помощи instead of?

create table t (id int primary key, fld float)
create view v as select id, fld * 10 as x from t

insert v(id, x) values (1, 5)
--Update or insert of view or function 'v' failed because it contains a derived or constant field.

create trigger tr1 on v instead of insert as
insert t (id, fld) select id, x/10 from inserted

insert v(id, x) values (1, 5)

select * from t

id fld
----------- -----------------------------------------------------
1 0.5

(1 row(s) affected)
7 апр 03, 17:44    [166963]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
gardenman
Member

Откуда: С-Петербург
Сообщений: 2347
вообще-тоя триггер before в DB2 использавал примерно след. образом

CREATE TRIGGER MyTrig1
NO CASCADE BEFORE INSERT ON MyTable
FOR ESCH ROW (может быть FOR EACH STATEMENT)
REFERENCING NEW AS N
MODE DB2SQL
BEGIN ATOMIC
SET N.MyField1=(SELECT *офигительный запрос*);
SET N.MyField2=( );
END

или

CREATE TRIGGER MyTrig2
NO CASCADE BEFORE INSERT ON MyTable
FOR ESCH ROW (может быть FOR EACH STATEMENT)
REFERENCING NEW AS N
MODE DB2SQL
WHEN (Какое-то условие с селектами и всякими проверками)
SIGNAL SQLSTATE '7500X' ('текст ошибки')

Т.е. можно задать несколько триггеров на одну таблицу
Триггеры выполняются в порядке создания.
7 апр 03, 17:47    [166968]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Roman Ignatiev
Member

Откуда: Москва
Сообщений: 680
Не пробовал... Но дело в том, что после выполнения before будет попытка вставить запись во view, а оно не обновляемое. Избежать этого можно только дав Exception в триггере, а это откатит всю транзакцию :-))
7 апр 03, 17:48    [166970]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
nick
Member

Откуда: Москва
Сообщений: 129
2Дед Маздай
"Если нужно вставлять много записей (insert ... select), то мне кажется, мой вариант будет быстрее, потому что он срабатывает сразу для всех вставляемых записей, а не идет по каждой, как курсор. "
Не будет. Потому что никакого курсора нет, так так используется строчный тригер.
И как ты собираешься использовать свой тригер для моей задачи("срабатывает сразу для всех вставляемых записей")???
7 апр 03, 17:57    [166985]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Дед Маздай
Member

Откуда:
Сообщений: 655
Строчный триггер = идет позаписьно. Чем это отличается от курсора?
В Oracle есть возможность выбирать for statement / for row, как нам это демонстрировал gardenman в случае DB2?
7 апр 03, 18:09    [166998]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
nick
Member

Откуда: Москва
Сообщений: 129
Я не совсем понял как там у DB.
Просто в Oracle перед тем как вставить данные в строку выполняется тригер before for each row
и все тело тригера выглядит так
if :new.latname is null then
:new.latname:=fun(:new.rusname);
end if;
никакого курсора нет
7 апр 03, 18:16    [167006]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
tygra
Member

Откуда: Тверь (Иркутск, Край)
Сообщений: 9997
Вообще по поводу триггеров Before и After:
тут все удобство/неудобство зависит только от привычки.
Работал я раньше на InterBase - использовал Before.
Потом переход на MS SQL тоже был тяжел в этом отношении - как так без Before.
Но ничего, привык. Теперь уж и не хочется ничего менять Before. И нет проблем.
7 апр 03, 18:30    [167024]     Ответить | Цитировать Сообщить модератору
 Re: Триггеры  [new]
Alexander_Chepack
Member

Откуда: London
Сообщений: 22649

Триггеров на системные события как таковых нет, но при желании всегда
можно сделать их на системные таблицы


А лучше всего (при желании) прежде чем писать что-то, самому проверить.
Триггеры на системные таблицы в SQL Server сделать НЕВОЗМОЖНО.
7 апр 03, 18:41    [167035]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Сравнение СУБД Ответить