Триггер проверяет, равны ли некоторые значения в некоторой строке таблицы, затем обновляет, если нет, то вставляет

#sql #postgresql #triggers

#sql #postgresql #триггеры

Вопрос:

У меня проблема с триггером в psql, который должен проверить, существуют ли уже некоторые значения (отправитель, получатель, тема) в таблице, и если они существуют, мне нужно обновить только одно значение (subject = RE: subject) в этой строке, если нет, то мне нужно вставить новую строку.

 CREATE OR REPLACE FUNCTION check_theme()
RETURNS TRIGGER
AS $$
    DECLARE e BOOLEAN;
    BEGIN
        e := EXISTS(
            SELECT *
            FROM message
            WHERE sender = NEW.sender
              AND reciever = NEW.reciever
              AND subject = NEW.subject
            );
        IF NOT e THEN
            INSERT INTO message(sender, reciever, subject, text)
            VALUES(NEW.sender, NEW.reciever, NEW.subject, NEW.text);
        ELSE
            UPDATE message
            SET subject = 'Re: ' || NEW.subject
            WHERE sender = NEW.sender
              AND reciever = NEW.reciever
              AND subject = NEW.subject;
        END IF;
        RETURN NEW;

    END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER theme_check
BEFORE INSERT OR UPDATE
ON message
FOR EACH ROW EXECUTE PROCEDURE check_theme(); 
  

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

Что я делаю не так?

Комментарии:

1. BEFORE INSERT Триггер должен просто сказать IF e THEN NEW.subject = 'Re: ' || NEW.subject; . Однако я не уверен, чего вы хотите в AFTER UPDATE случае… Вы действительно хотите, чтобы обновления запускали новые вставки в таблицу?

2. Чтобы было понятнее, мне нужно решить эту проблему: реализовать триггер и запустить соответствующую функцию «check_theme», которая для каждой записи в таблице сообщений будет проверять, есть ли уже сообщение от того же отправителя, получателя и с тем же заголовком. Если есть, измените заголовок, чтобы включить префикс «Re:» Пример: Заголовок «Привет» изменится на «Re: Привет», если такие темы уже есть. Если нет, то вам нужно вставить новое сообщение.

Ответ №1:

Через несколько дней я понял, что мои знания о том, как работают триггеры, были неверными.. итак, моя ошибка заключалась в том, что я добавлял функцию INSERT, но вставка будет выполнена в любом случае, если не было сообщения с тем же отправителем, получателем и заголовком.Вот почему я всегда получал инфинитивный цикл. Итак, код, который будет работать, приведен ниже

 CREATE OR REPLACE FUNCTION provjera_teme()
RETURNS TRIGGER
AS $$
    DECLARE postoji BOOLEAN;
    BEGIN
        postoji := EXISTS(
            SELECT poruka
            FROM poruka
            WHERE posiljatelj = NEW.posiljatelj
              AND primatelj = NEW.primatelj
              AND (naslov = NEW.naslov OR naslov LIKE 'Re: ' || NEW.naslov)
            );    
        IF postoji THEN
            UPDATE poruka
            SET naslov = 'Re: ' || naslov
            WHERE posiljatelj = NEW.posiljatelj
                  AND primatelj = NEW.primatelj
                  AND naslov = NEW.naslov AND naslov NOT LIKE 'Re%';
                RETURN NULL;
        END IF;
        RETURN NEW;
    END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER tema_provjera
BEFORE INSERT
ON poruka
FOR EACH ROW EXECUTE PROCEDURE provjera_teme();