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

发布于 2024-11-28 07:30:15 字数 1362 浏览 5 评论 0原文

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

I have two tables representing two different types of imagery. I am using PostGIS to represent the boundaries of those images. Here is a simplified example of those tables:

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)
);

I also have a cross reference table, which I want to contain all the IDs of the images that overlap each other. Whenever an image of type "A" gets inserted into the database, I want to check to see whether it overlaps any of the existing imagery of type "P" (and vice versa) and insert corresponding entries into the img_a_img_p cross reference table. This table should represent a many-to-many relationship.

My first instinct is to write a trigger to manage thisimg_a_img_p table. I've never created a trigger before, so let me know if this is a silly thing to do, but it seems to make sense to me. So I create the following trigger:

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();

The part where I am getting stuck is with writing the trigger function. My code is in Java and I see that there are tools like PL/pgSQL, but I'm not sure if that's what I should use or if I even need one of those special add-ons.

Essentially all I need the trigger to do is update the cross reference table each time a new image gets inserted into either img_format_a or img_format_p. When a new image is inserted, I would like to use a PostGIS function like ST_Intersects to determine whether the new image overlaps with any of the images in the other table. For each image pair where ST_INTERSECTS returns true, I would like to insert a new entry into img_a_img_p with the ID's of both images. Can someone help me figure out how to write this trigger function? Here is some pseudocode:

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

枕头说它不想醒 2024-12-05 07:30:15

您可以将通常的 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;

触发器有两个额外的变量,


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


数据类型记录;保存旧数据库行的变量,用于行级触发器中的 UPDATE/DELETE 操作。该变量在语句级触发器和 INSERT 操作中为 NULL。

因此,您可以使用 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 语句之前。

You could wrap the usual INSERT ... SELECT idiom in a PL/pgSQL function sort of like this:

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;

Triggers have two extra variables, NEW and OLD:

NEW
Data type RECORD; variable holding the new database row for INSERT/UPDATE operations in row-level triggers. This variable is NULL in statement-level triggers and for DELETE operations.

OLD
Data type RECORD; variable holding the old database row for UPDATE/DELETE operations in row-level triggers. This variable is NULL in statement-level triggers and for INSERT operations.

So you can use NEW.id to access the new img_format_p value that's going in. You (currently) can't use the plain SQL language for triggers:

It is not currently possible to write a trigger function in the plain SQL function language.

but PL/pgSQL is pretty close. This would make sense as an AFTER INSERT trigger:

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

Deletes could be handled with a foreign key on img_a_img_p and a cascading delete. You could use your trigger for UPDATEs as well:

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();

but you'd probably want to clear out the old entries before inserting the new ones with something like:

delete from img_a_img_p where img_p_id = NEW.id;

before the INSERT...SELECT statement.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文