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

Откуда: Казань
Сообщений: 7217
Есть домен
CREATE DOMAIN DMN_BOOL_2 AS
SMALLINT
DEFAULT 0
NOT NULL
CHECK (VALUE IN (0,1));

и табля
CREATE TABLE TBL_PHONE (
    ID                    INTEGER NOT NULL,
    FK_PEOPLE             INTEGER NOT NULL,
    MAIN_CONTACT          DMN_BOOL_2 DEFAULT 1
-- <skiped>
);


Нужно реализовать на триггере: для всех ID у одного FK_PEOPLE сделать MAIN_CONTACT = 0, если у одному из них делается MAIN_CONTACT = 1

1. где реализовать, в BeforeInsert/Update?
2. как?

был бы благодарен за пример или пинок в нужном направлении
=================
Док.

Win10 Ultim x64/Deb 10 amd64/Darwin Cocoa:
FB 3.0.7.33374, Lazarus 2.3.0(trunk); FPC 3.3.1(trunk)

Сообщение было отредактировано: 8 окт 21, 11:05
8 окт 21, 11:15    [22381107]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 11092
Док,

1. Лучше в after
2. что-то вроде того

....
begin
  IF (:NEW.MAIN_CONTACT = 1 AND :NEW.MAIN_CONTACT  <> :OLD.MAIN_CONTACT ) THEN -- второе условие только для update
  BEGIN
     UPDATE TBL_PHONE
     SET MAIN_CONTACT = 0
     WHERE FK_PEOPLE = :NEW.FK_PEOPLE  
        AND MAIN_CONTACT = 1
        AND ID <> :NEW.ID; -- это условие только update триггере
  END
end


З.Ы. я не люблю такие триггеры

Сообщение было отредактировано: 8 окт 21, 11:14
8 окт 21, 11:24    [22381114]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
KreatorXXI
Member

Откуда: Москва
Сообщений: 1119
Док,

чего сложного? В After Update типа такого:
if new.main_contact=1 then
  update tbl_phone a
  set a.main_contact=0
  where a.fk_people=new.fk_people and a.id<>new.id

Подводных камней не вижу.
8 окт 21, 11:35    [22381124]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Док
Member

Откуда: Казань
Сообщений: 7217
Гуд. Спасибо за примеры. Чуть позже опробую и отпишусь
8 окт 21, 12:01    [22381135]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3811
Док, я бы сделал иначе - создал ещё одну таблицу MAIN_PHONE с полями PEOPLE_ID (PK и FK к PEOPLES) и PHONE_ID (FK к TBL_PHONE). Потом создал бы VIEW на TBL_PHONE с LEFT JOIN к MAIN_PHONE по PEOPLE_ID и с вычисляемым полем BOOL на MAIN_PHONE.PHONE_ID IS NOT NULL. Не пришлось бы возиться с триггером.
8 окт 21, 12:29    [22381151]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Док
Member

Откуда: Казань
Сообщений: 7217
rdb_dev,

ага, вместо одного триггера две таблицы? Оккама плачет :)
8 окт 21, 19:44    [22381401]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Док
Member

Откуда: Казань
Сообщений: 7217
Вобщем, сделал так:
IF (NEW.MAIN_CONTACT = 1) THEN
  BEGIN
  UPDATE TBL_PHONE PH
     SET PH.MAIN_CONTACT = 0
   WHERE (PH.FK_PEOPLE = NEW.FK_PEOPLE) AND (PH.ID <> NEW.ID);
  END


Причем, работает как в before, так и в after insert/update

Еще раз спасибо за помощь

Сообщение было отредактировано: 8 окт 21, 20:02
8 окт 21, 20:13    [22381408]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Док,

если у тебя есть поле FK_PEOPLE - значит, у тебя есть табличка PEOPLE.
Во в ней и размести ссылку на майн контакт.
И триггеров не понадобится. И выборку делать проще будет.
8 окт 21, 20:34    [22381418]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
kdv
Member

Откуда: iBase.ru
Сообщений: 30244
Док
Причем, работает как в before, так и в after insert/update

ну, делать триггер before, в котором update, это как-то нелогично. А в after самое то.
8 окт 21, 22:17    [22381445]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
hvlad
Member

Откуда:
Сообщений: 11551
Док
Вобщем, сделал так:
А теперь посмотри внимательно и сам скажи - почему ты выбрал вариант, который гораздо хуже этого 22381114
8 окт 21, 22:37    [22381455]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Док
Member

Откуда: Казань
Сообщений: 7217
hvlad,
С виду опасностей не вижу...

ъъъъъ
Во в ней и размести ссылку на майн контакт.

КМК, не подойдет. В моем понимании, реализовывать консистентность логики и данных надо на уровне сервера, а не клиента.

Если я правильно тебя понял, я должен закольцевать таблички. Тогда при изменении MAIN_CONTACT я еще должен буду в TBL_PEOPLE менять ФК на TBL_PHONE.ID той записи, которая теперь является основным контактом. А это еще триггер. Circulus viciosus получается.
8 окт 21, 22:51    [22381458]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Док
hvlad,
С виду опасностей не вижу...

ъъъъъ
Во в ней и размести ссылку на майн контакт.

КМК, не подойдет. В моем понимании, реализовывать консистентность логики и данных надо на уровне сервера, а не клиента.

Если я правильно тебя понял, я должен закольцевать таблички. Тогда при изменении MAIN_CONTACT я еще должен буду в TBL_PEOPLE менять ФК на TBL_PHONE.ID той записи, которая теперь является основным контактом. А это еще триггер. Circulus viciosus получается.


Как раз наоборот, логика из императивной становится декларативной, в итоге отпадает необходимость в триггерах вообще.
Поле MAIN_CONTACT таблички TBL_PHONE становится ненужным. Для назначения "главной записи" меняется значение ссылки в табличке PEOPLE, вот и всё.
8 окт 21, 23:05    [22381463]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Док
Member

Откуда: Казань
Сообщений: 7217
ъъъъъ,

изящно. Только мне на клиенте нужно отображать ВСЕ имеющиеся на данный момент у человека телефоны, из которых один является основным :)
8 окт 21, 23:19    [22381468]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Док
Только мне на клиенте нужно отображать ВСЕ имеющиеся на данный момент у человека телефоны, из которых один является основным :)

Ну вот, смотри.

CREATE TABLE PEOPLE (
    ID             INTEGER NOT NULL,
    FIO            VARCHAR(255),
    MAIN_PHONE_ID  INTEGER /* Вот он*/
);


CREATE TABLE PHONE (
    ID         INTEGER NOT NULL,
    PEOPLE_ID  INTEGER,
    NMBR       VARCHAR(40) /* Значение номера */
);
9 окт 21, 00:44    [22381488]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Добавляем данные:

INSERT INTO PEOPLE (ID, FIO, MAIN_PHONE_ID) VALUES (1, 'Иванов Иван Иванович', 1);
INSERT INTO PEOPLE (ID, FIO, MAIN_PHONE_ID) VALUES (2, 'Петров Петр Петрович', 3);
INSERT INTO PEOPLE (ID, FIO, MAIN_PHONE_ID) VALUES (3, 'Васильев Василий Васильевич', NULL);

INSERT INTO PHONE (ID, PEOPLE_ID, NMBR) VALUES (1, 1, '222-22-2222-22');
INSERT INTO PHONE (ID, PEOPLE_ID, NMBR) VALUES (2, 1, '333-33-3333-33');
INSERT INTO PHONE (ID, PEOPLE_ID, NMBR) VALUES (3, 2, '444-44-4444-44');
INSERT INTO PHONE (ID, PEOPLE_ID, NMBR) VALUES (4, 2, '555-55-5555-55');
INSERT INTO PHONE (ID, PEOPLE_ID, NMBR) VALUES (5, 3, '666-66-6666-66');
INSERT INTO PHONE (ID, PEOPLE_ID, NMBR) VALUES (6, 3, '777-77-7777-77');

Т.е., у Иванова главный телефон это 222-22-2222-22, у Петрова - 444-44-4444-44, а у Васильева - нет.
9 окт 21, 00:46    [22381489]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Добавим констреинтов:
ALTER TABLE PHONE ADD CONSTRAINT UNQ_PHONE_PEOPLE UNIQUE (PEOPLE_ID, ID);


ALTER TABLE PEOPLE ADD CONSTRAINT PK_PEOPLE PRIMARY KEY (ID);
ALTER TABLE PHONE ADD CONSTRAINT PK_PHONE PRIMARY KEY (ID);


ALTER TABLE PEOPLE ADD CONSTRAINT FK_PEOPLE_MAIN_PHONE FOREIGN KEY (ID, MAIN_PHONE_ID) REFERENCES PHONE (PEOPLE_ID, ID);
ALT


Составной ключ в констреинте для того, чтобы пиплу не назначили главным чужой номер. Если бизнеслогика этого не требует - составной ключ не нужен.
9 окт 21, 00:47    [22381490]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Список всех пиплов, с их основными номерами:

select P.ID, P.FIO, PH.NMBR as MAIN_PHONE
from PEOPLE P
left join PHONE PH on PH.ID = P.MAIN_PHONE_ID   


К сообщению приложен файл. Размер - 3Kb
9 окт 21, 00:49    [22381491]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Док,

И, наконец,
Док
мне на клиенте нужно отображать ВСЕ имеющиеся на данный момент у человека телефоны, из которых один является основным :)

-
select PH.ID, PH.NMBR, iif(P.ID is not null, 'Main', null) IS_MAIN_PHONE
from PHONE PH
left join PEOPLE P on P.MAIN_PHONE_ID = PH.ID
where PH.PEOPLE_ID = :PEOPLE_ID   


Например, для :PEOPLE_ID равным 1, результат:

К сообщению приложен файл. Размер - 2Kb
9 окт 21, 00:56    [22381492]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
hvlad
Member

Откуда:
Сообщений: 11551
Док
С виду опасностей не вижу...
Твой триггер апдейтит все записи (кроме текущей) с таким же FK_PEOPLE - а достаточно только одной.
Причём делает он это после любого апдейта "главной" записи, даже если MAIN_CONTACT не менялось.

PS способ 22381418 гораздо лучше
9 окт 21, 11:38    [22381556]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Док
Member

Откуда: Казань
Сообщений: 7217
ъъъъъ,

Понял. Тоже вариант, конечно. Спасибо.

hvlad
Твой триггер апдейтит все записи (кроме текущей) с таким же FK_PEOPLE - а достаточно только одной.

Ага, вот ты о чем. Согласен, конечно, апдейтить ВСЕ записи телефонов одного ФК - не комильфо. С другой стороны, ну сколько телефонов м.б. у пациента в базе? Сервер и не заметит :)

Способ Дениса универсальнее и правильнее (возьму на заметку "в целях повышения общей образованности" ©), а способ KreatorXXI - в моем случае практичнее, КМК.
9 окт 21, 12:01    [22381562]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
hvlad
Member

Откуда:
Сообщений: 11551
Док,

кто я такой, чтобы учить доктора соблюдать гигиену и не применять кривые методы лечения ?
9 окт 21, 14:19    [22381601]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
Док
Member

Откуда: Казань
Сообщений: 7217
hvlad,

Влад, я не спорю. Просто до меня иногда долго доходит :)

А так кошерно будет?
CREATE OR ALTER TRIGGER TBL_PHONE_AIU0 FOR TBL_PHONE
ACTIVE AFTER INSERT OR UPDATE POSITION 0
AS
BEGIN
IF (NEW.MAIN_CONTACT = 1) THEN
  BEGIN
  UPDATE TBL_PHONE PH
     SET PH.MAIN_CONTACT = 0
   WHERE (PH.FK_PEOPLE = NEW.FK_PEOPLE) AND (PH.ID <> NEW.ID) AND (PH.MAIN_CONTACT = 1);
  END
END

Вроде работает (и на вставку и на апдейт) и обновляет только те записи, которые надо изменить
9 окт 21, 17:01    [22381649]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
ъъъъъ
Member

Откуда:
Сообщений: 2653
Вот лентяй...
10 окт 21, 00:07    [22381791]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
hvlad
Member

Откуда:
Сообщений: 11551
Док
А так кошерно будет?
Ты учёл ровно половину рекомендаций.
Учтёшь вторую - получится триггер как у Дениса.
И нужно ещё что-то делать с удалениями, или не нужно - тут тебе виднее.
10 окт 21, 00:24    [22381793]     Ответить | Цитировать Сообщить модератору
 Re: Нужна помощь с написанием триггера  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3811
Док
rdb_dev,
ага, вместо одного триггера две таблицы? Оккама плачет :)
Док, почему нет? Во-первых, в данном случае, две таблицы, это лучший вариант нормализации, а во-вторых, триггер создаёт больше хлопот, так как, при изменении основного контакта, для обеспечения целостности тебе надо блокировать на изменение все записи контактов врача до подтверждения транзакции лишь ради изменения флага. Впрочем, хозяин - барин...

Сообщение было отредактировано: 11 окт 21, 08:56
11 окт 21, 09:03    [22382021]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Firebird, InterBase Ответить