在动态查询中使用几何数据类型
Use geometry data type in dynamic query
我正在使用 PostGIS 在 PostgreSQL 中创建一个函数,我在其中接受表名和点的几何形状,我想在函数内部的查询中使用它们......
CREATE OR REPLACE FUNCTION trial(tbl text[],tag text[],geo geometry)
RETURNS boolean AS
$BODY$
DECLARE i integer;
DECLARE len integer;
DECLARE result boolean;
DECLARE bool boolean;
BEGIN
result=true;
SELECT ARRAY_LENGTH(tbl,1) INTO len;
FOR i IN 1..len LOOP
EXECUTE format('select st_dwithin(geo::geography,geom::geography,1) from %s where name=any(array[%s]) and st_dwithin(geo::geography,geom::geography,1)=true',tbl[i],tag[i]) into bool;
IF (bool!=true) THEN
result=false;
EXIT;
END IF;
END LOOP;
return result;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
这显示了我的错误
LINE 1: select st_dwithin(geo::geography,geom::geography,1) from grn...
当我使用
%s for that geometry
我得到下一个错误
ERROR: syntax error at or near "AA40E9A0E5440F498329474092A40"
LINE 1: select st_dwithin(0101000020E6100000002AA40E9A0E5440F4983294...
我是 PostgreSQL 的初学者...在这种情况下我可以使用什么格式说明符?????
您的函数存在一些问题。
首先,在format()
函数中你只能拼接标识符和文字值,而你需要传递一个geography
和一个text[]
,你的函数的两个参数.这基本上意味着您不能使用 format()
函数,而应该使用 use the USING
clause。顺便说一下,这是个好消息,因为 format()
生成一个字符串,而且效率很低(你传入一个 geometry
,它被 format()
转换为字符串,然后解析回 geometry
在服务器中,每次循环迭代一次)。 geo
参数是一个 PL/pgSQL 变量,不会被 EXECUTE
解析,因此它也必须通过 USING
子句提供。
动态查询本身也写得不是特别好。如果至少有 1 行具有 tags
之一,并且位于 geo
的 1 米范围内,则逻辑表明您想要 return true
。有效地编写,该查询将是:
SELECT 1 FROM <table>
WHERE name = ANY(<tags>)
AND ST_DWithin(<geo>, geom::geography, 1, false)
LIMIT 1;
这显然假设所有 table 都有一个 name
和 geom
列。如果 geom
是 geography
类型,则可以省略转换。使用 false
进行球体计算,这对于这种短距离来说绰绰有余,而且计算速度更快。
连同一些流程逻辑改进,您的函数将变为:
CREATE OR REPLACE FUNCTION trial(tbl text[], tag text[], geo <b>geography</b>)
RETURNS boolean AS $BODY$
DECLARE
t text;
res int;
BEGIN
<b>FOREACH t IN ARRAY tbl LOOP </b>
EXECUTE 'SELECT 1 FROM ' || quote_ident(t) ||
' WHERE name = ANY()' ||
' AND ST_DWithin(, geom::geography, 1, false) ' ||
'LIMIT 1'
INTO res USING tags, geo;
<b>IF res IS NULL THEN</b> -- No value was returned so no nearby points
<b>RETURN false;</b>
END IF;
END LOOP;
<b>RETURN true;</b> -- If we get here, all tables have at least 1 match
END;
$BODY$ LANGUAGE plpgsql;
此函数采用 table 名称数组,然后确定所有 table 是否至少有 1 个点具有指定点 1 米范围内的任何提供的标签。这对我来说听起来不太有用。返回一组 text
,每行给出符合(或不符合)该标准的 table 的名称看起来更有用,甚至可能是 RETURNS TABLE (tbl name, num int, tags text[])
版本给出每个 table 1 米以内的点数以及该点的匹配标签 table。
我正在使用 PostGIS 在 PostgreSQL 中创建一个函数,我在其中接受表名和点的几何形状,我想在函数内部的查询中使用它们......
CREATE OR REPLACE FUNCTION trial(tbl text[],tag text[],geo geometry)
RETURNS boolean AS
$BODY$
DECLARE i integer;
DECLARE len integer;
DECLARE result boolean;
DECLARE bool boolean;
BEGIN
result=true;
SELECT ARRAY_LENGTH(tbl,1) INTO len;
FOR i IN 1..len LOOP
EXECUTE format('select st_dwithin(geo::geography,geom::geography,1) from %s where name=any(array[%s]) and st_dwithin(geo::geography,geom::geography,1)=true',tbl[i],tag[i]) into bool;
IF (bool!=true) THEN
result=false;
EXIT;
END IF;
END LOOP;
return result;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
这显示了我的错误
LINE 1: select st_dwithin(geo::geography,geom::geography,1) from grn...
当我使用
%s for that geometry
我得到下一个错误
ERROR: syntax error at or near "AA40E9A0E5440F498329474092A40"
LINE 1: select st_dwithin(0101000020E6100000002AA40E9A0E5440F4983294...
我是 PostgreSQL 的初学者...在这种情况下我可以使用什么格式说明符?????
您的函数存在一些问题。
首先,在format()
函数中你只能拼接标识符和文字值,而你需要传递一个geography
和一个text[]
,你的函数的两个参数.这基本上意味着您不能使用 format()
函数,而应该使用 use the USING
clause。顺便说一下,这是个好消息,因为 format()
生成一个字符串,而且效率很低(你传入一个 geometry
,它被 format()
转换为字符串,然后解析回 geometry
在服务器中,每次循环迭代一次)。 geo
参数是一个 PL/pgSQL 变量,不会被 EXECUTE
解析,因此它也必须通过 USING
子句提供。
动态查询本身也写得不是特别好。如果至少有 1 行具有 tags
之一,并且位于 geo
的 1 米范围内,则逻辑表明您想要 return true
。有效地编写,该查询将是:
SELECT 1 FROM <table>
WHERE name = ANY(<tags>)
AND ST_DWithin(<geo>, geom::geography, 1, false)
LIMIT 1;
这显然假设所有 table 都有一个 name
和 geom
列。如果 geom
是 geography
类型,则可以省略转换。使用 false
进行球体计算,这对于这种短距离来说绰绰有余,而且计算速度更快。
连同一些流程逻辑改进,您的函数将变为:
CREATE OR REPLACE FUNCTION trial(tbl text[], tag text[], geo <b>geography</b>)
RETURNS boolean AS $BODY$
DECLARE
t text;
res int;
BEGIN
<b>FOREACH t IN ARRAY tbl LOOP </b>
EXECUTE 'SELECT 1 FROM ' || quote_ident(t) ||
' WHERE name = ANY()' ||
' AND ST_DWithin(, geom::geography, 1, false) ' ||
'LIMIT 1'
INTO res USING tags, geo;
<b>IF res IS NULL THEN</b> -- No value was returned so no nearby points
<b>RETURN false;</b>
END IF;
END LOOP;
<b>RETURN true;</b> -- If we get here, all tables have at least 1 match
END;
$BODY$ LANGUAGE plpgsql;
此函数采用 table 名称数组,然后确定所有 table 是否至少有 1 个点具有指定点 1 米范围内的任何提供的标签。这对我来说听起来不太有用。返回一组 text
,每行给出符合(或不符合)该标准的 table 的名称看起来更有用,甚至可能是 RETURNS TABLE (tbl name, num int, tags text[])
版本给出每个 table 1 米以内的点数以及该点的匹配标签 table。