До и после триггера по одному и тому же событию? Заполнить дочернюю таблицу PostgreSQL

Ситуация

У меня есть база данных в PostgreSQL 9.5, используемая для хранения местоположения объектов по времени.

У меня есть основная таблица с именем «позиция» со столбцами (только релевантными):

  • position_id
  • position_timestamp
  • object_id

Он разбит на 100 дочерних таблиц по object_id с условием:

CREATE TABLE position_object_id_00
( CHECK object_id%100 = 0 ) 
INHERITS ( position );

И так далее для остальных детей. Я разделил с отношением модуля, чтобы равномерно распределить объекты. Каждый дочерний элемент индексируется по position_id and object_id (два разных индекса).

Триггер для перенаправления вставок на дочерние элементы:

 CREATE TRIGGER insert_position_trigger
     BEFORE INSERT ON position
     FOR EACH ROW EXECUTE PROCEDURE insert_position();

И процедура insert_position() ищет правильную дочернюю таблицу для вставки данных, вставляет ее и возвращает НОВЫЙ объект:

CREATE OR REPLACE FUNCTION insert_position() RETURNS TRIGGER AS $insert_position$
  DECLARE

  BEGIN
    --Look for child table
    [...]
    --Insert data in right child table
    [...]

    RETURN NEW;
  END;
$insert_position$ LANGUAGE plpgsql;

У меня есть сводная таблица object_last_known_position с теми же столбцами, которые обновляются с помощью триггера:

CREATE TRIGGER update_object_last_known_position 
   AFTER INSERT OR UPDATE ON position 
   FOR EACH ROW
   EXECUTE PROCEDURE update_object_last_known_position();

Процедура update_object_last_known_position() в основном проверяет, является ли position_timestamp более новым, затем удаляет старую запись и создает новую запись с данными, переданными в запросе INSERT или UPDATE (NEW).

Проблема

Таким образом, эти два триггера реагируют на одно и то же событие: вставка в позицию, один до, другой после Возврат нового для insert_position() позволяет мне использовать NEW в триггере update_object_last_known_position(), а это абсолютно необходимо. Но при этом он также вставляет данные о позиции главной таблицы. Итак, мои данные теперь дублируются.

Пробовал ставить два триггера раньше, они оба выполняются при вставке данных если я так разрешу, но если я уберу "return new" из процедуры insert_position(), update_object_last_known_position() не выполняется.

Я застрял в этой проблеме, и я не нашел способа выполнить оба этих триггера без заполнения позиции главной таблицы при вставке данных.

Так что, если есть идеи, буду очень признателен :)

Спасибо за помощь!

ИЗМЕНИТЬ

Решение

Благодаря ответу

Я «объединил» два своих триггера: insert_position() теперь вызывает update_object_last_known_position напрямую. Для этого я изменил update_object_last_known_position на хранимую процедуру с параметром. Параметр - это идентификатор только что созданной позиции insert_position(), поэтому я могу найти ее и получить информацию. (Вызов update_object_last_known_position внутри другого триггера означает, что мы больше не можем использовать NEW) И, очевидно, тип возвращаемого значения для insert_position() теперь NULL, и все работает нормально :)


person Miwauke    schedule 25.08.2016    source источник
comment
Было бы полезно иметь более полный код, но похоже, что вы вставляете новую строку в update_object_last_known_position(), а также вставляете (чтобы запустить триггер). Не могли бы вы просто не вставить строку в update_object_last_known_position()   -  person Philip Couling    schedule 25.08.2016
comment
Строка, вставленная в основную таблицу, связана не с update_object_last_known_position(), а с insert_position(). Поскольку это триггер перед возвратом NEW, я думаю, он не останавливает INSERT. И мне нужно вставить строку в object_last_known_position, это часть дизайна: мне нужно сохранить последнюю позицию, чтобы иметь лучшую производительность при запросе.   -  person Miwauke    schedule 25.08.2016


Ответы (1)


Если я вас правильно понял, вы пытаетесь:

  1. Остановить вставку и заменить ее вставкой в ​​другую таблицу (определяется триггером)
  2. Обновите сводную таблицу (delete/insert), чтобы она указывала на новую строку.

Ваша проблема в том, что 1 мешает 2 произойти? Это логично, потому что вы остановили вставку, поэтому вы также остановили любую обработку вставки.

Итак, чтобы решить эту проблему, у вас есть несколько вариантов (варианты 1 и 2 аналогичны)

  1. Вызов update_object_last_known_position() из insert_position() и только один триггер
  2. Создайте метод-оболочку для insert_position() и update_object_last_known_position() и используйте только один триггер.
  3. Поместите триггер для update_object_last_known_position() во все таблицы, в которые может вставляться insert_position().
person Philip Couling    schedule 25.08.2016