需要帮助编写PostgreSQL触发器函数

时间:2011-08-05 20:17:04

标签: postgresql triggers postgis

我有两张表代表两种不同类型的图像。我使用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)
);

我还有一个交叉引用表,我想要包含彼此重叠的图像的所有ID。每当“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_aimg_format_p时更新交叉引用表。插入新图像时,我想使用像ST_Intersects这样的PostGIS函数来确定新图像是否与其他表中的任何图像重叠。对于ST_INTERSECTS返回true的每个图像对,我想在img_a_img_p中插入一个新条目,其中包含两个图像的ID。有人可以帮我弄清楚如何编写这个触发器功能吗?这是一些伪代码:

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 个答案:

答案 0 :(得分:4)

你可以在PL / pgSQL函数中包含通常的INSERT ... SELECT成语,如下所示:

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 and OLD

  


  数据类型RECORD;变量为行级触发器中的INSERT / UPDATE操作保存新数据库行。在语句级触发器和DELETE操作中,此变量为NULL。

     

<强> OLD
  数据类型RECORD;变量在行级触发器中保存旧数据库行以进行UPDATE / DELETE操作。在语句级触发器和INSERT操作中,此变量为NULL。

因此,您可以使用NEW.id来访问新的img_format_p值。您(当前)can't use the plain 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();

可以使用foreign key on img_a_img_p and a cascading delete处理删除。您也可以将触发器用于UPDATE:

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陈述之前