在动态查询中使用几何数据类型

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 都有一个 namegeom 列。如果 geomgeography 类型,则可以省略转换。使用 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。