use*_*583 5 postgresql dynamic-sql plpgsql postgis
我想对ST_Intersection(clipper_geom, clipped_geom)
来自表的行数执行。
https://postgis.net/docs/ST_Intersection.html
https://postgis.net/docs/ST_Intersects.html
POSTGIS 交集本身不支持处理多个几何图形,这与ST_Intersects()
我必须设计一个函数(返回一个表)来选择与我的clipper_geom
using相交的行ST_Intersects()
、循环遍历结果集并计算与 的每个交集有关ST_Intersection()
。字段geom
和clipped_geom_wkt
是记录剪裁几何体的字段。
该功能有效,但我需要为每个要生成剪辑的表使用不同的功能。我想动态读取输入表(列名称和类型)并在RETURN
语句中定义两者。
所有字段名称和类型都相同,只是geom
更新和clipped_geom_wkt
添加。
我尝试搜索 Stack Overflow,找到了有关如何创建动态表结构的示例,但没有一个LOOP
对第一个结果执行后续操作,其中列名必须匹配才能插入/更新新数据。
这是我到目前为止所提出的,但我不确定如何执行该LOOP
部分、添加clipped_geom_wkt
字段和更新geom
字段。一些回复建议RETURNS TABLE (...)
如果添加更多字段SETOF
...
但似乎动态生成的列仅支持RETURNS SETOF ...
CREATE OR REPLACE FUNCTION clip_palin_polygon_complete(clipped_table text,clipper_geom text, age_sequence VARCHAR)
RETURNS TABLE (rec clipped_table, clipped_geom_wkt text)) AS $$ --not sure if this is the right way to do it...
DECLARE var_r record;
BEGIN
FOR var_r IN (
SELECT * FROM clipped_table
WHERE clipped_table.seq IN (age_sequence)
AND ST_Intersects(ST_GeomFromText(clipper_geom,4326), clipped_table.geom)
)
LOOP
/*
these are the original table fields that I would like to keep and match
dynamically with any table I have as input (clipped_table)
objectid := var_r.objectid;
seq := var_r.seq;
-- etc.
*/
--below there are the only two fields that need modifying
geom := (
SELECT ST_Intersection(ST_GeomFromText(clipper_geom, 4326), var_r.geom) AS geom);
clipped_geom_wkt := (
SELECT
ST_AsText(ST_Intersection(ST_GeomFromText(clipper_geom,4326), var_r.geom)) AS clipped_geom_wkt);
RETURN NEXT;
END LOOP;
END; $$
LANGUAGE 'plpgsql'
Run Code Online (Sandbox Code Playgroud)
您应该能够用一个简单的SELECT
方法来避免所有的并发症:
SELECT t.*, ST_Intersection(x.geom, t.geom) AS geom2
FROM tbl t -- replace tbl with actual table
JOIN ST_GeomFromText($clipper_geom, 4326) AS x(geom) ON ST_Intersects(x.geom, t.geom)
WHERE t.seq = $age_sequence;
Run Code Online (Sandbox Code Playgroud)
细微差别:您得到原始结果geom
和geom2
结果的交集。如果您确实需要,请将多余的内容添加ST_AsText(ST_Intersection(x.geom, t.geom)) AS clipped_geom_wkt
到列表中。SELECT
我是这样理解你的问题的:
我有各种输入表,每个输入表都有一列geom geometry
。我想要一个函数接受表名clipper_geom geometry
作为输入并返回与我的clipper_geom
. 应添加一列clipped_geom_wkt text
并更改值geom
,每列显示与 的交集clipper_geom
。
这不是小事。SQL是一种静态语言,函数最晚需要在调用时知道返回类型。我们可以使用多态类型实现动态结果,但我们需要一个众所周知的行类型来使用。现有表的行类型适合它,但您想附加另一列。这并不容易实现。解决方法是返回多态行类型,加上一个额外的列(就像您似乎已经尝试过一样)。分解函数调用中的行类型以获得所需的结果:
CREATE OR REPLACE FUNCTION my_func(_tbl ANYELEMENT
, _clipper_geom text
, _age_sequence text)
RETURNS TABLE (tbl ANYELEMENT, clipped_geom_wkt text)
LANGUAGE plpgsql AS
$func$
DECLARE
_geom geometry := ST_GeomFromText(_clipper_geom, 4326); -- compute once
BEGIN
FOR tbl IN EXECUTE format(
'SELECT * FROM %s
WHERE seq = $1
AND ST_Intersects($2, geom)'
, pg_typeof(_tbl)
)
USING _age_sequence, _geom -- data types must match!
LOOP
tbl := json_populate_record(tbl, json_build_object('geom', ST_Intersection(_geom, tbl.geom)));
clipped_geom_wkt := ST_AsText(tbl.geom);
RETURN NEXT;
END LOOP;
END
$func$
Run Code Online (Sandbox Code Playgroud)
致电(重要!):
SELECT (tbl).*, clipped_geom_wkt
FROM my_func(NULL::public.clipped_table, $my_clipper_geom, $my_age_sequence);
Run Code Online (Sandbox Code Playgroud)
在 Postgres 10 中为我工作。
tbl
是如何在子句中隐式定义的RETURNS
,它动态复制输入类型 ( ANYELEMENT
)。因此,您不必SETOF
像您推测的那样使用多态类型。FOR-IN-EXECUTE
循环动态查询。json_populate_record()
。看:
(tbl).*
我坚持你上面的设计,但对于给定的例子来说这是不必要的复杂化。额外的列完全是多余的,只需从函数调用中clipped_geom_wkt
派生即可。geom
然后我们就可以直接使用输入类型了:
CREATE OR REPLACE FUNCTION my_func2(_tbl ANYELEMENT
, _clipper_geom text
, _age_sequence text)
RETURNS SETOF ANYELEMENT
LANGUAGE plpgsql AS
$func$
DECLARE
_geom geometry := ST_GeomFromText(_clipper_geom, 4326);
BEGIN
FOR _tbl IN EXECUTE format(
'SELECT * FROM %s
WHERE seq = $1
AND ST_Intersects($2, geom)'
, pg_typeof(_tbl)
)
USING _age_sequence, _geom -- data types must match!
LOOP
_tbl := json_populate_record(_tbl, json_build_object('geom', ST_Intersection(_geom, _tbl.geom)));
RETURN NEXT _tbl;
END LOOP;
END
$func$;
Run Code Online (Sandbox Code Playgroud)
致电(重要!):
SELECT *, ST_AsText(geom) AS clipped_geom_wkt -- if you need the redundant column
FROM my_func2(NULL::public.clipped_table, $my_clipper_geom, $my_age_sequence);
Run Code Online (Sandbox Code Playgroud)