Возможно ли создать триггерную функцию добавляющую значение в две таблицы, если в одной из таблиц значение уже занято primary key?

Прошу помощи с проблемой.

Есть две простейшие таблицы.

CREATE TABLE primer1 (id INT PRIMARY KEY, s TEXT );

CREATE TABLE primer2 (id INT, s TEXT);

С добавленными туда значениями:

INSERT INTO primer1 VALUES (1, 'a'), (2, 'b');

INSERT INTO primer2 VALUES (2, 'c');

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

Пишу простую функцию, делаю триггер:

CREATE OR REPLACE FUNCTION function1()                                
RETURNS TRIGGER                                                                 
AS $$                                                                           
BEGIN
INSERT INTO primer2(id, s) VALUES (NEW.id, NEW.s);                    
RETURN NEW;                                                                     
END;                                                                            
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger1                                             
AFTER INSERT ON primer1                                                             
FOR EACH ROW                                                                    
EXECUTE PROCEDURE function1(); 

Все работает до момента попытки добавить запись со значением id равным 2, прописав это через INSERT INTO primer1, так как значение 2 уже занято как Primary Key.

Возможно ли это вообще?

Пытался переделывать функции различными способами,например:

CREATE OR REPLACE FUNCTION primer2()
RETURNS TRIGGER AS  $$                                                          
DECLARE                                                                         
exist_id INT;                                                                   
BEGIN                                                                           
SELECT id INTO exist_id FROM primer1 WHERE s = NEW.s LIMIT 1;                   
IF NOT FOUND THEN                                                               
insert into primer3 (id, s) values (NEW.id, NEW.s);                             
end if;                                                                         
insert into primer4 (id, s) values (NEW.id, NEW.s);                             
return new;                                                                     
end;                                                                            
$$ language plpgsql;

Но либо не работает, либо выходят ошибки.Менял срабатывание триггера AFTER/BEFORE тоже безрезультатно.

Просьба подсказать возможно ли создать функцию, которая будет проверять значение в первой таблице, не выдавая ошибку в связи с занятым как Primary Key значением, если таковое присутствует и добавлять значение во вторую таблицу?


Ответы (1 шт):

Автор решения: Diyor Khakimov
  1. Если не менять структуру таблицы то: Можно написать функцию, которая будет проверять наличие id в primer1, если он уже есть то вставлять только в primer2.

     CREATE OR REPLACE FUNCTION insert_data(p_id INT, p_s TEXT)
     RETURNS VOID AS $$
     DECLARE
        exists_count INT;
     BEGIN
        SELECT COUNT(*) INTO exists_count FROM primer1 WHERE id = p_id;
    
         IF exists_count = 0 THEN
             INSERT INTO primer1(id, s) VALUES (p_id, p_s);
         END IF;
         INSERT INTO primer2(id, s) VALUES (p_id, p_s);
     END;
     $$ LANGUAGE plpgsql;
    
  2. Сделай primer1.id не PRIMARY KEY, а UNIQUE и использовать ON CONFLICT

     INSERT INTO primer1(id, s)
     VALUES (2, 'c')
     ON CONFLICT (id) DO NOTHING;
    
  3. Также можно использовать BEFORE INSERT триггер, который перенаправляет вставку:

     CREATE OR REPLACE FUNCTION redirect_insert()
     RETURNS TRIGGER AS $$
     DECLARE
         exists_id INT;
     BEGIN
     SELECT id INTO exists_id FROM primer1 WHERE id = NEW.id;
     IF FOUND THEN
         -- Вставка только в primer2
         INSERT INTO primer2(id, s) VALUES (NEW.id, NEW.s);
         RETURN NULL; -- Прервать вставку в primer1
     ELSE
         -- Вставка продолжается и AFTER-триггер сработает
         RETURN NEW;
     END IF;
     END;
     $$ LANGUAGE plpgsql;
    
     -- BEFORE trigger
     CREATE TRIGGER primer1_before_insert
     BEFORE INSERT ON primer1
     FOR EACH ROW
     EXECUTE FUNCTION redirect_insert();
    
     -- AFTER trigger to insert into primer2
     CREATE OR REPLACE FUNCTION copy_to_primer2()
     RETURNS TRIGGER AS $$
     BEGIN
         INSERT INTO primer2(id, s) VALUES (NEW.id, NEW.s);
         RETURN NEW;
     END;
     $$ LANGUAGE plpgsql;
    
     CREATE TRIGGER primer1_after_insert
     AFTER INSERT ON primer1
     FOR EACH ROW
     EXECUTE FUNCTION copy_to_primer2();
    
→ Ссылка