Нужна помощь в написании триггерной функции PostgreSQL - PullRequest
0 голосов
/ 06 августа 2011

У меня есть две таблицы, представляющие два разных типа изображений.Я использую PostGIS для представления границ этих изображений.Вот упрощенный пример этих таблиц:

CREATE TABLE img_format_a (
    id SERIAL PRIMARY KEY,
    file_path VARCHAR(1000),
    boundary GEOGRAPHY(POLYGON, 4326)
);

CREATE TABLE img_format_p (
    id SERIAL PRIMARY KEY,
    file_path VARCHAR(1000),
    boundary GEOGRAPHY(POLYGON, 4326)
);

У меня также есть таблица перекрестных ссылок, в которую я хочу включить все идентификаторы изображений, которые перекрывают друг друга.Всякий раз, когда изображение типа «A» вставляется в базу данных, я хочу проверить, не перекрывает ли оно какое-либо из существующих изображений типа «P» (и наоборот), и вставить соответствующие записи в таблицу перекрестных ссылок img_a_img_p.,Эта таблица должна представлять отношение «многие ко многим».

Мой первый инстинкт - написать триггер для управления этой таблицей img_a_img_p.Я никогда раньше не создавал триггера, поэтому дайте мне знать, если это глупо, но мне кажется, что это имеет смысл.Поэтому я создаю следующий триггер:

CREATE TRIGGER update_a_p_cross_reference
    AFTER INSERT OR DELETE OR UPDATE OF boundary
    ON img_format_p FOR EACH ROW
    EXECUTE PROCEDURE check_p_cross_reference();

Часть, в которой я застреваю - это написание функции триггера.Мой код написан на Java, и я вижу, что есть такие инструменты, как PL / pgSQL, но я не уверен, что это то, что я должен использовать, или мне даже нужна одна из этих специальных надстроек.

По существу всеМне нужен триггер, чтобы обновлять таблицу перекрестных ссылок каждый раз, когда новое изображение вставляется в img_format_a или img_format_p.Когда вставляется новое изображение, я хотел бы использовать функцию PostGIS, например ST_Intersects, чтобы определить, перекрывает ли новое изображение какое-либо из изображений в другой таблице.Для каждой пары изображений, где ST_INTERSECTS возвращает true, я хотел бы вставить новую запись в img_a_img_p с идентификаторами обоих изображений.Может кто-нибудь помочь мне понять, как написать эту функцию триггера?Вот некоторый псевдокод:

SELECT * FROM img_format_p P
    WHERE ST_Intersects(A.boundary, P.boundary);

for each match in selection {
    INSERT INTO img_a_img_p VALUES (A.id, P.id);
}

1 Ответ

4 голосов
/ 06 августа 2011

Вы можете обернуть обычную идиому INSERT ... SELECT в функцию PL / pgSQL вроде этого:

create function check_p_cross_reference() returns trigger as
$$
begin
    insert into img_a_img_p (img_a_id, img_p_id)
    select a.id, p.id
    from img_format_a, img_format_p
    where p.id = NEW.id
      and ST_Intersects(a.boundary, p.boundary);
    return null;
end;
$$ language plpgsql;

Триггеры имеют две дополнительные переменные, NEW и OLD:

NEW
Тип данных ЗАПИСЬ; переменная, содержащая новую строку базы данных для операций INSERT / UPDATE в триггерах уровня строки. Эта переменная равна NULL в триггерах уровня оператора и для операций DELETE.

OLD
Тип данных ЗАПИСЬ; переменная, содержащая старую строку базы данных для операций UPDATE / DELETE в триггерах уровня строки. Эта переменная равна NULL в триггерах уровня операторов и для операций INSERT.

Таким образом, вы можете использовать NEW.id для доступа к новому входящему значению img_format_p. Вы (в настоящее время) не можете использовать простой язык SQL для триггеров:

В настоящее время невозможно написать функцию триггера на простом языке функций SQL.

но PL / pgSQL довольно близок. Это имеет смысл как триггер AFTER INSERT:

CREATE TRIGGER update_a_p_cross_reference
AFTER INSERT
ON img_format_p FOR EACH ROW
EXECUTE PROCEDURE check_p_cross_reference();

Удаление может быть обработано с помощью внешнего ключа на img_a_img_p и каскадного удаления . Вы также можете использовать свой триггер для ОБНОВЛЕНИЙ:

CREATE TRIGGER update_a_p_cross_reference
AFTER INSERT OR UPDATE OF boundary
ON img_format_p FOR EACH ROW
EXECUTE PROCEDURE check_p_cross_reference();

но вы, вероятно, захотите очистить старые записи перед тем, как вставлять новые, например:

delete from img_a_img_p where img_p_id = NEW.id;

до оператора INSERT...SELECT.

...