#postgresql #triggers #sql-insert #plpgsql
#postgresql #триггеры #sql-вставка #plpgsql
Вопрос:
У меня есть таблица ( time TIMESTAMP PRIMARY KEY, pressure REAL NOT NULL
). Мне нужно разработать пару триггер / функция, которая делает это: при вставке новой записи либо обновите существующую запись, либо вставьте новую запись в зависимости от метки времени.
Код триггера:
CREATE TRIGGER trigger_insert
BEFORE INSERT ON mytable
FOR EACH ROW
EXECUTE PROCEDURE func_insert();
Метод функции:
create or replace function func_insert()
returns trigger
language plpgsql
as
$$
DECLARE
time_exists TIMESTAMP;
BEGIN
IF pg_trigger_depth() <> 1 THEN
RETURN NEW;
END IF;
SELECT time INTO time_exists FROM mytable WHERE time = NEW.time;
IF NOT FOUND THEN
INSERT INTO mytable VALUES(NEW.*);
ELSE
UPDATE mytable SET pressure = NEW.pressure WHERE time = NEW.time;
END IF;
RETURN NEW;
END;
$$;
Обсуждение:
-
Без
IF pg_trigger_depth() <> 1 THEN
условия сценарий приводит к исключению переполнения триггера глубины. -
Проблема в том, что я получаю ошибку при вставке первой (sic!) записи в пустую (sic!) таблицу:
psycopg2.ошибки.Уникальное нарушение: повторяющееся значение ключа нарушает уникальное ограничение «mytable_key» ПОДРОБНО: Ключ («время»)=(2019-06-01 00:00:00) уже существует.
Спасибо.
Ответ №1:
Если строка должна быть вставлена, просто верните new
вместо того, чтобы пытаться вставить ее снова.
Если строка должна быть обновлена, не возвращайте, new
иначе она будет вставлена…
При этом выполнение upsert является самым чистым решением
INSERT INTO myTable (time, pressure) VALUES (..., ...)
ON CONFLICT (time)
DO UPDATE SET pressure = EXCLUDED.pressure;