【问题标题】:'syntax error at or near "VARCHAR"' in DECLARE section when trying to create function尝试创建函数时在 DECLARE 部分中的“VARCHAR”处或附近出现语法错误
【发布时间】:2016-03-21 05:06:38
【问题描述】:

我创建了以下存储过程,它应该返回与多边形组有交集的所有位置名称(没有不同的...与 3 个多边形相交 => 3 个名称)

CREATE OR REPLACE FUNCTION get_name_without_distinct_by_polygon_group(start_time TIMESTAMP,
                                                                      end_time TIMESTAMP,
                                                                      polygon_group_id INTEGER)
RETURNS TABLE(name_name_name_name VARCHAR(12)) AS $$
DECLARE
  name VARCHAR(12);
  poly_id INTEGER;
BEGIN
  FOR poly_id IN (SELECT polygon_id 
                  FROM polygon_group_members 
                  WHERE group_id = poly_id)
    LOOP
      FOR name IN (SELECT DISTINCT name
                   FROM location, polygons
                   WHERE location.timestamp BETWEEN start_time AND end_time
                        AND poly_id = polygons.id
                        AND st_intersects(location.polygon, polygons.polygon))
      LOOP
        RETURN NEXT name;
      END LOOP;
  END LOOP;
  RETURN;
END;

$$ LANGUAGE SQL;

当我尝试创建此函数时,出现以下错误:

[42601] 错误:“VARCHAR”位置或附近的语法错误:356

基于 PostgreSQL declaration documentation 似乎没问题...

到目前为止我已经尝试过:

  • 我把name VARCHAR(12);改成了name location.mac%TYPE

  • 我把name VARCHAR(12);改成了name RECORD

  • 我更改了声明的范围,然后在 poly_id INTEGER; 上遇到了同样的错误

  • 我把LANGUAGE SQL改成了postgressql

  • 我用谷歌搜索了它,根据任何示例/问题,我发现这个过程应该可以工作。

【问题讨论】:

标签: sql postgresql plpgsql user-defined-functions stored-functions


【解决方案1】:

您不需要为此使用 PL/pgSQL。循环是不必要的,会使一切变得非常缓慢。

据我所知应该这样做:

CREATE OR REPLACE FUNCTION get_name_without_distinct_by_polygon_group(start_time TIMESTAMP,
                                                                      end_time TIMESTAMP,
                                                                      polygon_group_id INTEGER)
   RETURNS TABLE(name_name_name_name VARCHAR(12)) 
AS 
$$
  SELECT DISTINCT name
  FROM location, polygons
  WHERE location.timestamp BETWEEN start_time AND end_time
    AND poly_id IN (SELECT polygon_id  FROM polygon_group_members WHERE group_id = polygon_group_id)
    AND st_intersects(location.polygon, polygons.polygon));
$$ 
LANGUAGE SQL;

我还认为条件WHERE group_id = poly_id 是错误的,因为您使用的变量应该将结果存储在where 子句中。我认为您的意思是使用WHERE group_id = polygon_group_id(我在上面的代码中更改了它)


当使用language sql 时,您不能使用像begin ... end 这样的过程代码或声明变量。

错误ERROR: syntax error at or near "VARCHAR" Position: 356是由于在函数体内使用language sql但使用PL/pgSQL引起的。如果您在定义中将language sql 更改为language plpgsql,它应该可以工作(但同样,具有两个嵌套循环的解决方案效率不高)。

【讨论】:

  • 您对LANGUAGE plpgsql 是正确的(在您已删除的评论中...)然后我遇到了一个新错误,我正在处理它...但是正如我在问题中所写名称上没有区别(顺便说一句,位置名称不是主键)。第一个循环给了我组中的所有多边形。第二个循环给了我所有与多边形相交的 名称。该过程将返回所有没有不同的名称,因此如果一个位置与 3 个多边形相交(随着时间的推移,位置不固定)我将在结果中有 3 个名称...
【解决方案2】:

感谢@a_horse_with_no_name 的评论指出$$ LANGUAGE SQL 应该是$$ LANGUAGE plpgsql 我找到了解决方案。 在我更改为$$ LANGUAGE plpgsql 后,我收到了一个关于缺少OUT PARAMETER 的新错误,但是RETURN NEXT 不允许使用OUT PARAMETER,所以我不得不返回SETOF 而不是TABLE

CREATE OR REPLACE FUNCTION get_name_without_distinct_by_polygon_group(start_time TIMESTAMP,
                                                                      end_time TIMESTAMP,
                                                                      polygon_group_id INTEGER)
RETURNS SETOF VARCHAR(12) AS $$
DECLARE
  name VARCHAR(12);
  poly_id INTEGER;
BEGIN
  FOR poly_id IN (SELECT polygon_id 
                  FROM polygon_group_members 
                  WHERE group_id = poly_id)
    LOOP
      FOR name IN (SELECT DISTINCT name
                   FROM location, polygons
                   WHERE location.timestamp BETWEEN start_time AND end_time
                        AND poly_id = polygons.id
                        AND st_intersects(location.polygon, polygons.polygon))
      LOOP
        RETURN NEXT name;
      END LOOP;
  END LOOP;
  RETURN;
END;

$$ LANGUAGE plpgsql;

【讨论】:

  • 如果 a_horse 的回答像您所说的那样对您有用,请考虑实际投票给它 - 就像工具提示建议“这个答案很有用”一样。
  • @ErwinBrandstetter 实际上我投票赞成他的评论。他对已删除的问题发表了评论...他的回答根本没有帮助...但是您的回答比我的解决方案更好(+1并接受)。我只是等着测试它....
【解决方案3】:

您提出的答案仍然存在一些问题。你可以很好地使用RETURNS TABLE()。比较:

CREATE OR REPLACE FUNCTION get_name_without_distinct_by_polygon_group(start_time timestamp,
                                                                      end_time timestamp,
                                                                      polygon_group_id int)
  RETURNS TABLE(name_name_name_name VARCHAR(12)) AS
$func$
DECLARE
   name VARCHAR(12);  -- possible naming conflict!
   poly_id int;
BEGIN
   FOR poly_id IN  --  no parentheses needed
      SELECT polygon_id
      FROM   polygon_group_members 
      WHERE  group_id = poly_id  -- I suspect you really want polygon_group_id here
   LOOP
      FOR name_name_name_name IN  -- assign directly
         SELECT DISTINCT name  -- l.name or p.name??
         FROM   polygons p
         JOIN   location l ON st_intersects(l.polygon, p.polygon)
         WHERE  p.id = poly_id
         AND    l.timestamp BETWEEN start_time AND end_time
      LOOP
        RETURN NEXT;  -- already assigned
      END LOOP;
   END LOOP;
   RETURN;
END
$func$  LANGUAGE plpgsql;

注意可能的命名冲突。所有声明的变量和参数(包括 RETURNS TABLE() 子句中的字段在 plpgsql 或 SQL 函数的主体内的 SQL 查询中都是可见的。普遍的约定是在变量名称前加上 _ 并对查询中的所有列进行表限定. 查看今天早些时候的答案:

整个函数可能会被一个 SELECT 语句替换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    相关资源
    最近更新 更多