powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Нужна помощь в написании триггера
25 сообщений из 33, страница 1 из 2
Нужна помощь в написании триггера
    #39296717
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Имеется таблица с адресами примерно такой структуры
используемый домен
Код: sql
1.
2.
3.
4.
5.
CREATE DOMAIN DMN_BOOL_2 AS
SMALLINT
DEFAULT 0
NOT NULL
CHECK (VALUE IN (0,1));


сама табля с флагом прописки (PERMANENT_ADDRESS) и флагом текущего места жительства (CURRENT_ADDRESS)
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
CREATE TABLE TBL_ADDRESS (
    ID                    INTEGER NOT NULL,
    FK_PEOPLE             INTEGER NOT NULL,
    PERMANENT_ADDRESS     DMN_BOOL_2 DEFAULT 1,
    CURRENT_ADDRESS       DMN_BOOL_2 DEFAULT 1,
COUNTRY               DMN_STRING_100
);

ALTER TABLE TBL_ADDRESS ADD CONSTRAINT PK_TBL_ADDRESS PRIMARY KEY (ID);



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

=================
Док.

Win7 Ultim x64/Deb 7.6 i386 (Deb 8.3 i386):
FB 3.0.0.32483, диалект 3, SS(win)/CS(Deb),
Lazarus 1.7; FPC 3.1.1, IBX by -Rik-; IBE 2016.4.29.1
IBE 2016.5.14.1
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296723
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ой....

вот монстр
Код: sql
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.
SET TERM ^ ;
CREATE OR ALTER TRIGGER TBL_ADDRESS_BIU3 FOR TBL_ADDRESS
ACTIVE BEFORE INSERT OR UPDATE POSITION 3
AS
begin
IF (NEW.PERMANENT_ADDRESS = 1) /* если вставляемая/изменяемая запись содержит флаг прописки */
  THEN
    BEGIN
      IF (NEW.CURRENT_ADDRESS = 1) /* если вставляемая/изменяемая запись содержит флаг текущего места жительства */
        THEN /* проверяем, есть для для вставляемого FK_PEOPLE аналогичные записи для обоих флагов (PERMANENT_ADDRESS = 1 и CURRENT_ADDRESS = 1) */
          BEGIN
            IF (EXISTS(
                  SELECT A.ID
                  FROM TBL_ADDRESS A
                  WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.PERMANENT_ADDRESS  = 1) AND (A.CURRENT_ADDRESS = 1))
                      )
                )
              THEN /* сбрасываем флаги обоих признаков */
                BEGIN
                  UPDATE TBL_ADDRESS A
                  SET A.PERMANENT_ADDRESS = 0,
                      A.CURRENT_ADDRESS = 0
                  WHERE (A.FK_PEOPLE = NEW.FK_PEOPLE);
                END
          END
        ELSE /* проверяем, есть для для вставляемого FK_PEOPLE аналогичные записи для флага прописки(PERMANENT_ADDRESS = 1) */
          BEGIN
            IF (EXISTS(
                  SELECT A.ID
                  FROM TBL_ADDRESS A
                  WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.PERMANENT_ADDRESS  = 1))
                      )
                )
              THEN /* сбрасываем флаг прописки */
                BEGIN
                  UPDATE TBL_ADDRESS A
                  SET A.PERMANENT_ADDRESS = 0
                  WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.PERMANENT_ADDRESS = 1));
                END
          END
    END
  ELSE
    IF (NEW.CURRENT_ADDRESS = 1) /* если вставляемая/изменяемая запись содержит флаг текущего места жительства */
      THEN /* проверяем, есть для для вставляемого FK_PEOPLE аналогичные записи флага текущего места жительства(CURRENT_ADDRESS = 1) */
        BEGIN
            IF (EXISTS(
                  SELECT A.ID
                  FROM TBL_ADDRESS A
                  WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.CURRENT_ADDRESS  = 1))
                      )
                )
              THEN /* сбрасываем флаг текущего места жительства */
                BEGIN
                  UPDATE TBL_ADDRESS A
                  SET A.CURRENT_ADDRESS = 0
                  WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.CURRENT_ADDRESS = 1));
                END
        END
end
^
SET TERM ; ^



При попытке выполнить в Эскперте ( и isql) такой скрипт
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
INSERT INTO TBL_ADDRESS (ID, FK_PEOPLE, PERMANENT_ADDRESS, CURRENT_ADDRESS, COUNTRY) VALUES (NULL, 1, 1, 1, 'Россия');
COMMIT;

INSERT INTO TBL_ADDRESS (ID, FK_PEOPLE, PERMANENT_ADDRESS, CURRENT_ADDRESS, COUNTRY) VALUES (NULL, 1, 0, 0, 'Уганда');
COMMIT;

INSERT INTO TBL_ADDRESS (ID, FK_PEOPLE, PERMANENT_ADDRESS, CURRENT_ADDRESS, COUNTRY) VALUES (NULL, 1, 1, 0, 'Украина');
COMMIT;


После третьего коммита получаю
Код: sql
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.
Too many concurrent executions of the same request.
Too many concurrent executions of the same request.
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 35, col: 19
At trigger 'TBL_ADDRESS_BIU3' line: 53, col: 19
At trigger '...
 



В принципе, возможно реализовать такой функционал или мне надо пересматривать структуру таблицы?
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296724
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
зы. с одним вообще, никаких проблем
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296730
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AFTER триггер не будет правильнее ?
Возможно придётся ещё и записи с NEW.ID исключить из запросов
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296869
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hvlad,
че-та лыжи не едут
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
SET TERM ^ ;
CREATE OR ALTER TRIGGER TBL_ADDRESS_AIU1 FOR TBL_ADDRESS
ACTIVE AFTER INSERT OR UPDATE POSITION 1
AS
begin
IF (NEW.PERMANENT_ADDRESS = 1) THEN /* если вставляемая/изменяемая запись содержит флаг прописки */
  BEGIN
    IF (EXISTS(
          SELECT RDB$DB_KEY
          FROM TBL_ADDRESS A
          WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (OLD.PERMANENT_ADDRESS  = 1))
              )
        )
      THEN /* сбрасываем флаг прописки */
        BEGIN
          UPDATE TBL_ADDRESS A
          SET A.PERMANENT_ADDRESS = 0
          WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (OLD.PERMANENT_ADDRESS = 1));
        END
  END
end
^
SET TERM ; ^


Хотел уточнить: до коммита вставленная запись уже подпадает в контекст OLD или еще нет?
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296880
KreatorXXI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док, объясните, как в таблице данные хранятся? Неправильно в триггере апдейтить ту же таблицу. Сервер позволяет, но в чём смысл?
Для вставляемой записи вообще нет нотификации old, только new.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296886
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
KreatorXXI,

Код, приведенный в первых двух постах сабжа таки работает в BI триггере. Осталось корректно реализовать задачу при апдейте данных (занимаюсь ).

Табля содержит список адресов (бывших и нынешних) для субъектов TBL_PEOPLE. В контексте приложения иногда надо указывать (например, в титульном листе амб. карты) адрес прописки и проживания отдельно.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296887
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доквозможно реализовать такой функционал или мне надо пересматривать структуру таблицы?

Оно, конечно, возможно, но лично я бы пересмотрел структуру таблиц: текущий адрес человека
хранил прямо в таблице людей, а в историю его переездов уже сбрасывал бы этот адрес
триггером при изменении.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296890
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ДокВ контексте приложения иногда надо указывать (например, в титульном листе амб. карты)
адрес прописки и проживания отдельно.

А в каком документе нужна история перемещения человека?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296891
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Докче-та лыжи не едутОтсюда этого не видно. Рекурсии нет больше ? Требуемая логика до сих пор остаётся загадкой...

ДокХотел уточнить: до коммита вставленная запись уже подпадает в контекст OLD или еще нет?Коммит тут вообще не при чём.
В операции INSERT нет и быть не может ничего "старого" (OLD) - только новое (NEW).
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296899
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakovлично я бы пересмотрел структуру таблиц
наверное, так будет логичнее и правильнее

Dimitry SibiryakovА в каком документе нужна история перемещения человека?
ХЗ, Дим, я просто пытаюсь реализовать то,что видел в быту и на работе


hvladВ операции INSERT нет и быть не может ничего "старого" (OLD) - только новое (NEW)
твои слова "AFTER" и "NEW.ID" почему-то были интерпретированы мной, как совет использовать OLD, сильно поколебав мое вроде бы устоявшееся мировоззрение и заставив пристально перечитывать LR в поисках упущенного тайного смысла OLD

Короче, ночью или в перерывах между приемами пациентов ничего придумывать нельзя. Щас, приеду на обед, подумаю над всем выше сказанным. Спасибо.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296903
KreatorXXI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakov,
я бы сделал бы так (если принципиально обходиться одной таблицей). Оставил бы один признак (0-прописка, 1 - проживание). И добавил бы дату. При печати определял бы адреса с максимальными датами. Вместо даты можно использовать первичный ключ.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296912
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
KreatorXXI,

что тормозило бы простейшие выборки на получение людей и их текущего адреса. Денормализация (текущий адрес в главной таблице а история смены адресов в подчинённой) в данном случае благо.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296918
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ДокDimitry SibiryakovА в каком документе нужна история перемещения человека?
ХЗ, Дим, я просто пытаюсь реализовать то,что видел в быту и на работе

Как человек, уже прошедший по этим граблям, советую: не пытайся сделать БД всего-всего.
Храни только минимально необходимую информацию.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296941
Фотография kdv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ДокToo many concurrent executions of the same request.
рекурсия?
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39296954
KreatorXXI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис,

Я привёл как вариант. Конечно, правильно для человека текущую информацию хранить в одной таблице, а историю в другой, меняется не только адрес, но и паспорт, фамилия и т.д. Может у Док'а так и есть, а приведённая таблица только для примера.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39297219
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kdvрекурсия?
да, оставил код только в BI, не ругается

Dimitry SibiryakovКак человек, уже прошедший по этим граблям
"Никогда не знаешь, что придет в голову этим пчелам" ©

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

В данном конкретном случае мне, как Таблоиду, уже интересен принципиальный момент: получится ли. Помучаюсь немного ;)
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39297262
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кажется, проблема решена. Владу отдельное спасибо за пинок в нужную сторону :)
Код: sql
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.
SET TERM ^ ;

CREATE OR ALTER TRIGGER TBL_ADDRESS_AIU0 FOR TBL_ADDRESS
ACTIVE AFTER INSERT OR UPDATE POSITION 0
AS
begin

IF ((NEW.PERMANENT_ADDRESS = 1) /* если у новой/изменяемой записи есть флаг прописки */
    AND
     /* для текущего FK_PEOPLE уже есть записи с таким же флагом */
    EXISTS(
      SELECT A.ID
      FROM TBL_ADDRESS A
      WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.PERMANENT_ADDRESS  = 1) AND (A.RDB$DB_KEY <> NEW.RDB$DB_KEY))
          )
    )
  THEN /* сбрасываем флаг прописки у остальных, кроме вставляемой/изменяемой */
    BEGIN
      UPDATE TBL_ADDRESS A
      SET A.PERMANENT_ADDRESS = 0
      WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.PERMANENT_ADDRESS  = 1) AND (A.RDB$DB_KEY <> NEW.RDB$DB_KEY));
    END
--------------------------------------------------------------
IF ((NEW.CURRENT_ADDRESS = 1) /* если у новой/изменяемой записи есть флаг текущего места жительства */
    AND
     /* для текущего FK_PEOPLE уже есть записи с таким же флагом */
    EXISTS(
      SELECT A.ID
      FROM TBL_ADDRESS A
      WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.CURRENT_ADDRESS  = 1) AND (A.RDB$DB_KEY <> NEW.RDB$DB_KEY))
          )
    )
  THEN /* сбрасываем флаг текущего места жительства у остальных, кроме вставляемой/изменяемой */
    BEGIN
      UPDATE TBL_ADDRESS A
      SET A.CURRENT_ADDRESS = 0
      WHERE ((A.FK_PEOPLE = NEW.FK_PEOPLE) AND (A.CURRENT_ADDRESS  = 1) AND (A.RDB$DB_KEY <> NEW.RDB$DB_KEY));
    END
end
^

SET TERM ; ^

...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39297272
KreatorXXI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док,
Интересно, а может пользователь снять флаги сам? Если может, то что происходит?
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39297278
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
KreatorXXI,

чтоб совсем не было прописки и постоянного места жительства? Может. Хоть из клиента, хоть прямой правкой базы.

Он не может выставить для конкретного человека две прописки и/или два постоянных места жительства.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39297634
KreatorXXI
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док,
для меня странно, база адресов есть, а адреса прописки и адреса постоянного проживания нет.
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39297900
Andrey_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Я бы сделал такой тригер немного переформатировав if-ы:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
if (NEW.PERMANENT_ADDRESS = 1) and (NEW.CURRENT_ADDRESS = 1) then
  update set PERMANENT_ADDRESS = 0, CURRENT_ADDRESS = 0
    where (FK_PEOPLE = NEW.FK_PEOPLE) and (ID <> NEW.ID) and
      (NEW.PERMANENT_ADDRESS = 1) and (NEW.CURRENT_ADDRESS = 1)
else if (NEW.PERMANENT_ADDRESS = 1) then
  update set PERMANENT_ADDRESS = 0
    where (FK_PEOPLE = NEW.FK_PEOPLE) and (ID <> NEW.ID) and
      (NEW.PERMANENT_ADDRESS = 1)
else if (NEW.CURRENT_ADDRESS = 1) then
  update set CURRENT_ADDRESS = 0
    where (FK_PEOPLE = NEW.FK_PEOPLE) and (ID <> NEW.ID) and
      (NEW.CURRENT_ADDRESS = 1)


Вроде не так монстроидально выглядит. Проверки на то, есть что апдейтить или нет - не нужны, при апдейте все равно проверка отработает и если нечего апдейтить - ничего и не проапдейтит. Конечно для избежания холостых апдейтов можно еще и так: (NEW.PERMANENT_ADDRESS is distinct from OLD.PERMANENT_ADDRESS) or (NEW.CURRENT_ADDRESS is distinct from OLD.CURRENT_ADDRESS), но тогда надо разделять insert и update тригеры, а это лениво :)

И да, рекурсия в афтер тригере у тебя скорее из-за того что ты не проверяешь ID <> NEW.ID.

И ситуаций когда есть человек, у которого был адрес, а теперь нет, можно придумать много - умер, скрылся в неизвестном направлении, отсудили квартиру, был прописан с родителями - выписался... А история адресов с датами может пригодится в самых разных ситуациях.

И последнее, я бы не делал такой тригер вообще, а переложил бы эту функцию на приложение (именно с такой структурой таблиц как у тебя). Если бы у тебя был не FB, а например Oracle, ты получил бы ошибку table is mutating и опять страдал бы головной болью. В каком-нибудь MSSQL или Sybase был бы какой-то свой головняк. Уж лучше в приложение :)
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39298421
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey_Уж лучше в приложение :)
А потом какой-нибудь дурак вручную поправит базу, а приложение или сильно задумается при выборке, или возьмет первую, формально подходящую, запись. И будут вопли, что все работает неправильно :)

За код спасибо. У меня на первый взгляд примерно то же, но "своими словами". Потом гляну повнимательнее. Сейчас к "командировке" в Челнах ;)
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39298425
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
KreatorXXIДок,
для меня странно, база адресов есть, а адреса прописки и адреса постоянного проживания нет.
Значит, ты просто невнимательно читал топик. У каждого адреса есть фк на хозяина, флаг прописки и флаг фактического проживания, каждый из которых уникален для конкретного фк
...
Рейтинг: 0 / 0
Нужна помощь в написании триггера
    #39298430
Фотография Gallemar
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Док, дядька, прости что оффтоплю. Я тебе через блог вопрос задал,полюбопытствуй :)
...
Рейтинг: 0 / 0
25 сообщений из 33, страница 1 из 2
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Нужна помощь в написании триггера
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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