Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Объясните как сделать правельный триггер / 25 сообщений из 44, страница 1 из 2
08.07.2008, 11:46
    #35417092
Shagrat
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Есть таблицы в которых существует поле modify (timestamp without time zone) - это поле в которое записывается дата создания или изменения записи в таблицы.

Это поле обновляется через триггер по INSERT или UPDATE.

Тригер
Код: plaintext
1.
2.
3.
4.
CREATE TRIGGER ecus_modify
  BEFORE INSERT OR UPDATE
  ON ecus
  FOR EACH ROW
  EXECUTE PROCEDURE change_modify();

Функция
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
CREATE OR REPLACE FUNCTION change_modify()
  RETURNS "trigger" AS
$BODY$BEGIN
  IF NEW.modify = NULL THEN
    NEW.modify = now();
  END IF;  
  RETURN NEW;
END;$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION change_modify() OWNER TO postgres;

Только вот проблема. Иногда нужно самому изменять значение этого поля. Пишу:
Код: plaintext
1.
UPDATE ecus SET modify='2008-07-08 10:26:53.575' WHERE id= 2643 ;

Только вот это поле всеравно заменяется значением из тригера.

Теперь вопрос. Где у меня ошибка. И поясните всетаки смысл AFTER и BEFORE.

Я себе предстовлял это так что когда ставшь признак BEFORE то заполенеие происходит так:
Сначало создается запись, потом срабатывает BEFORE и заполняет поля (вернее сам заполняешь в процедуре если надо), потом заполняются поля которые передал в INSERT потом срабатывает AFTER - который в свою очередь может заполнить даные (вернее сам заполняешь в процедуре если надо). А потом происходит запись данных.
...
Рейтинг: 0 / 0
08.07.2008, 12:14
    #35417191
4321
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Код: plaintext
NEW.modify = NULL 
таки так низзя
Спросите у сервера
Код: plaintext
SELECT NULL =NULL
, посмотрите на результат

надо так.
Код: plaintext
NEW.modify IS NULL 
...
Рейтинг: 0 / 0
08.07.2008, 12:15
    #35417194
MySQLCraft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
IF NEW.modify IS NULL THEN
...
Рейтинг: 0 / 0
08.07.2008, 12:28
    #35417242
Kruchinin Pahan
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Shagrat
Код: plaintext
1.
  IF NEW.modify = NULL THEN


Ошибка здесь. Сравнение NULL с другими значениями всегда возвращает NULL. А NULL это и не True и не False.
См. также IS NULL, Coalesce
Shagrat
Теперь вопрос. Где у меня ошибка. И поясните всетаки смысл AFTER и BEFORE.

Я себе предстовлял это так что когда ставшь признак BEFORE то заполенеие происходит так:
Сначало создается запись, потом срабатывает BEFORE и заполняет поля (вернее сам заполняешь в процедуре если надо), потом заполняются поля которые передал в INSERT потом срабатывает AFTER - который в свою очередь может заполнить даные (вернее сам заполняешь в процедуре если надо). А потом происходит запись данных.
Слегка иначе...
0. Делаем INSERT/UPDATE
1. Подготавливается новый ROW нужного типа, для которого последовательно отрабатывают DEFAULT'ы.
2. ROW передается в триггеры BEFORE (в порядке наименований триггеров). Только в триггере BEFORE можно поменять строку и откатить INSERT/UPDATE вернув NULL. В AFTER такого не проканает.
3. Запускается проверка Constraint и т.д. для новой версии строки.
4. Запускается триггер AFTER, он уже не влияет на строку через NEW, зато можно быть уверенным, что если до сюда дошло, то строка будет добавлена в базу (разве вилку из розетки выдернут). Здесь можно откатить всю транзакцию RAISE EXCEPTION.
5. Если до сюда дошло, то версия строки еще после нескольких преобразований попадает в базу. Но это еще более отдельная песня.
...
Рейтинг: 0 / 0
08.07.2008, 12:41
    #35417316
Shagrat
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Теперь становиться ясно (алгоритм примерно я так и представлял).

Только вот всеравно не работает. Когда меняешь другое поле триггер теперь не срабатывает. Странно.

Код: plaintext
1.
UPDATE ecus SET type= 1  WHERE id= 2643 ;
SELECT id, modify FROM ecus WHERE id= 2643 ;

Дата не обновляется, а если изменять поле то изменяется.

Вот полные исходники:
Код: plaintext
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.
CREATE TABLE ecus
(
  id serial NOT NULL,
  "type" integer NOT NULL,
  "name" character varying( 255 ) NOT NULL,
  "comment" character varying( 255 ),
  modify timestamp without time zone,
  CONSTRAINT ecus_pid PRIMARY KEY (id)
)
WITH (OIDS=FALSE);

CREATE TRIGGER ecus_modify
  BEFORE INSERT OR UPDATE
  ON ecus
  FOR EACH ROW
  EXECUTE PROCEDURE change_modify();

CREATE OR REPLACE FUNCTION change_modify()
  RETURNS "trigger" AS
$BODY$BEGIN
  IF NEW.modify IS NULL THEN
    NEW.modify = now();
  END IF;  
  RETURN NEW;
END;$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION change_modify() OWNER TO postgres;

Подскажите ка всетаки это оживить.
...
Рейтинг: 0 / 0
08.07.2008, 13:09
    #35417430
MySQLCraft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Может быть 'modify' - зарезервированнное слово.
Возьми его везде в кавычки NEW.'modify'
...
Рейтинг: 0 / 0
08.07.2008, 13:28
    #35417505
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
MySQLCraftМожет быть 'modify' - зарезервированнное слово.
Возьми его везде в кавычки NEW.'modify'в SQL одинарные кавычки означают строковую константу. в pg используются двойные кавычки для экранирования идентификаторов.
...
Рейтинг: 0 / 0
08.07.2008, 13:29
    #35417506
4321
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
ShagratТеперь становиться ясно (алгоритм примерно я так и представлял).

Только вот всеравно не работает. Когда меняешь другое поле триггер теперь не срабатывает. Странно.

Код: plaintext
1.
UPDATE ecus SET type= 1  WHERE id= 2643 ;
SELECT id, modify FROM ecus WHERE id= 2643 ;

Дата не обновляется, а если изменять поле то изменяется.

Вот полные исходники:
Код: plaintext
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.
CREATE TABLE ecus
(
  id serial NOT NULL,
  "type" integer NOT NULL,
  "name" character varying( 255 ) NOT NULL,
  "comment" character varying( 255 ),
  modify timestamp without time zone,
  CONSTRAINT ecus_pid PRIMARY KEY (id)
)
WITH (OIDS=FALSE);

CREATE TRIGGER ecus_modify
  BEFORE INSERT OR UPDATE
  ON ecus
  FOR EACH ROW
  EXECUTE PROCEDURE change_modify();

CREATE OR REPLACE FUNCTION change_modify()
  RETURNS "trigger" AS
$BODY$BEGIN
  IF NEW.modify IS NULL THEN
    NEW.modify = now();
  END IF;  
  RETURN NEW;
END;$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION change_modify() OWNER TO postgres;

Подскажите ка всетаки это оживить.
гыгы. еслиб в том месте, где работает триггер было бы действительно
Код: plaintext
NEW.modify IS NULL 
, то после срабатывания апдейта без триггера стало бы
Код: plaintext
NEW.modify IS NULL 
. как кстати тогда было бы присваивать в триггере
Код: plaintext
NEW.smfld =NULL 
если мы бы хотели очистить...

можно проверять
Код: plaintext
NEW.modify IS NULL OR  NEW.modify = OLD.modify
, ну или
Код: plaintext
 NEW.modify IS DISTINCT FROM OLD.modify
, или же руками послать SET modify = NULL. а получить обновку.
...
Рейтинг: 0 / 0
08.07.2008, 13:38
    #35417536
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
ShagratТеперь становиться ясно (алгоритм примерно я так и представлял).

Только вот всеравно не работает. Когда меняешь другое поле триггер теперь не срабатывает. Странно.ничего странного, имхо у Вас проблема с логикой Вашего алгоритма. Попробуйте переформулировать задачу, абсолютно точно и подробно написать что именно Вы хотите что бы происходило :) например типа такого:
если вставляется новая запись с полем modify is null, то ....

если вставляется новая запись с полем modify > текущей даты, то ...

если вставляется новая запись с полем modify <= текущей даты, то ...

если обновляется запись в которой старое значение поля modify is null и новое значение поля modify is null, то ...
и так далее. тогда Вам имхо проще будет понять в чём у Вас проблема.
...
Рейтинг: 0 / 0
08.07.2008, 14:12
    #35417641
Shagrat
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Все просто.
Если вставляю или обновляю поле, без modify то дата ставится текущая сервера (тоесть триггером).

Если я сам прописываю в запросе поле modify то данные берутся из него.
...
Рейтинг: 0 / 0
08.07.2008, 14:17
    #35417656
Kruchinin Pahan
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
4321
Код: plaintext
NEW.modify IS NULL OR  NEW.modify = OLD.modify
, ну или
Код: plaintext
 NEW.modify IS DISTINCT FROM OLD.modify
, или же руками послать SET modify = NULL. а получить обновку.
Не получится. У него триггер на INSERT/UPDATE. OLD для INSERT не определен. Надо разгребать 2 ситуации. TG_OP = 'INSERT' AND NEW.Modify IS NULL и TG_OP = 'UPDATE' AND Coalesce(NEW.Modify != OLD.Modify, True)

Как-то так.
...
Рейтинг: 0 / 0
08.07.2008, 14:25
    #35417686
Shagrat
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Все это можно но я не пойму почему просто

Код: plaintext
NEW.modify = now();

нельзя поставить, при этом все условия и так выполняется. Данные передаваемые запросом, должны заполниться всеравно после AFTER.
...
Рейтинг: 0 / 0
08.07.2008, 14:52
    #35417801
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
ShagratВсе просто.
Если вставляю или обновляю поле, без modify то дата ставится текущая сервера (тоесть триггером).

Если я сам прописываю в запросе поле modify то данные берутся из него.
Вы ошибочно полагаете что не указанные в запросе обновления поля принимают значение null в тригере в псевдозаписе NEW, но это не так. не указанные в запросе поля заполняются _старыми_ значениями, поэтому Ваше условие "if new.modify is null then" сработает при обновлении только один раз - если у обновляемой записи в базе поле modify равно null.
...
Рейтинг: 0 / 0
08.07.2008, 15:49
    #35418011
Shagrat
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Я понимаю что значение принимается старое.

Мне непонятен другой факт. Последовательность присвоения значения.

Я полагаю что если вызов AFTER то это означает что событие возникнет перед заполнением полей из самого запроса.

Тоесть:
1. Поле заполняется старым значением
2. Вызов AFTER- в моем случаи заполнение в триггере (Достаточно без условий, простое присвоение)
3. Заполнение данными из самого запроса.
4. событие BEFORE (Как я понял там возможна только проверка данных).
5. Ну м сама запись данных в поле (Не учитываю транзакции, кеши, блокировки итд.)

Так вот вопрос почему, при запросе без поля modify данные, изменяет триггер. А при запросе с modify также данные заполняет триггер - но после не прописываются данные с самого запроса, а остаются триггерные. Получается триггер AFTER вызывается после заполнения данных самим запросом.

Тогда непонятно как сделать чтобы всетаки происходило по алгоритму описанному выше.
...
Рейтинг: 0 / 0
08.07.2008, 16:26
    #35418153
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
ShagratМне непонятен другой факт. Последовательность присвоения значения.

Я полагаю что если вызов AFTER то это означает что событие возникнет перед заполнением полей из самого запроса.

Тоесть:
1. Поле заполняется старым значением
2. Вызов AFTER- в моем случаи заполнение в триггере (Достаточно без условий, простое присвоение)
3. Заполнение данными из самого запроса.
4. событие BEFORE (Как я понял там возможна только проверка данных).
5. Ну м сама запись данных в поле (Не учитываю транзакции, кеши, блокировки итд.)брр... у Вас видимо описка и вместо AFTER следует читать BEFORE, а вместо BEFORE - AFTER ? :)

у Вас конкретно всё перепутано :) должно быть имхо вот так:

1. Поле заполняется старым значением
3. Заполнение данными из самого запроса.
2. Вызов BEFORE - в моем случаи заполнение в триггере (Достаточно без условий, простое присвоение)
5. Ну м сама запись данных в поле (Не учитываю транзакции, кеши, блокировки итд.)
4. событие AFTER (Как я понял там возможна только проверка данных). -- можно update делать, только главное не зациклиться :)
...
Рейтинг: 0 / 0
08.07.2008, 16:31
    #35418172
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
BEFORE (ПЕРЕД) и AFTER (ПОСЛЕ) - это относительно внесения изменений в таблицу, а не относительно получения данных из запроса.

в тригере BEFORE таблица _ещё не изменена_, в тригере AFTER - таблица _уже изменена_


--
„Истина — это вовсе не то, что можно убедительно доказать, это то, что
делает всё проще и понятнее“ — Антуан де Сент-Экзюпери
...
Рейтинг: 0 / 0
08.07.2008, 16:41
    #35418217
Shagrat
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Ой извините, напутал, Я так и и мел ввиду.
По логике я все правильно понимаю.

Так вот у меня и не работает. Эта логика

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE TRIGGER ecus_modify
  BEFORE INSERT OR UPDATE
  ON ecus
  FOR EACH ROW
  EXECUTE PROCEDURE change_modify();

CREATE OR REPLACE FUNCTION change_modify()
  RETURNS "trigger" AS
$BODY$BEGIN
  NEW.modify = now();
  RETURN NEW;
END;$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION change_modify() OWNER TO postgres;


Когда делаешь:
Код: plaintext
UPDATE ecus SET modify='2008-07-08 14:14:32.734' WHERE id= 2643 ;
Тогда дата устанавливается из триггера. А нужно (должна я так считаю по логике). Чтобы прописывалась из запроса.

Когда делаешь:
Код: plaintext
UPDATE ecus SET modify='2008-07-08 14:14:32.734' WHERE id= 2643 ;
Тогда все ок, тоесть тоже триггер прописывает дату - как и нужно.

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

Так всетаки получается ваша схема является правильной. - Если да то тогда действительно придется сравнивать старые данные данные.
...
Рейтинг: 0 / 0
08.07.2008, 18:19
    #35418564
MySQLCraft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
А не проще DEFAULT=now() определить и не париться с триггерами?
...
Рейтинг: 0 / 0
08.07.2008, 18:20
    #35418566
MySQLCraft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
DEFAULT now() без равно
...
Рейтинг: 0 / 0
08.07.2008, 18:54
    #35418656
4321
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
MySQLCraftDEFAULT now() без равнодефолт не прокатит. на апдейт автору тоже надо модифачить.
...
Рейтинг: 0 / 0
08.07.2008, 18:56
    #35418658
MySQLCraft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
4321 MySQLCraftDEFAULT now() без равнодефолт не прокатит. на апдейт автору тоже надо модифачить.
SET modify = NULL

Пожертвовать удобством ради скорости и простоты
...
Рейтинг: 0 / 0
08.07.2008, 18:56
    #35418659
Shagrat
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Нет. Потомучто я могу его сменить. А мне нужно чтобы оно менялось после каждого INSERT или UPDATE
...
Рейтинг: 0 / 0
08.07.2008, 19:10
    #35418699
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
MySQLCraft 4321 MySQLCraftDEFAULT now() без равнодефолт не прокатит. на апдейт автору тоже надо модифачить.
SET modify = NULL

Пожертвовать удобством ради скорости и простотыSET modify = NULL запишет в modify null, а не default. что бы был default нужно так и писать: set modify = default
...
Рейтинг: 0 / 0
09.07.2008, 00:37
    #35419037
MySQLCraft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
Ёшчто бы был default нужно так и писать: set modify = default Точно! Забыл.
...
Рейтинг: 0 / 0
09.07.2008, 00:50
    #35419044
MySQLCraft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните как сделать правельный триггер
ShagratНет. Потомучто я могу его сменить. А мне нужно чтобы оно менялось после каждого INSERT или UPDATE Зачем "после", когда можно "во время"? Во время INSERT будет установлено ваше значение либо автоматически значение по дефолту. Во время UPDATE Вам придется каждый раз добавлять в выражение , modify = default или ваше значение. Если Вам это трудно или Вы не доверяете своей программе или пользователям нужно иметь доступ для прямого UPDATE и при этом таблица должна сама себя мониторить тогда извините. Так ли это необходимо?
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Объясните как сделать правельный триггер / 25 сообщений из 44, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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