'syntax error at or near "VARCHAR"' 尝试创建函数时在 DECLARE 部分

'syntax error at or near "VARCHAR"' in DECLARE section when trying to create function

我创建了以下存储过程,它应该 return 所有与多边形组有交集的位置名称(没有明显的...与 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] ERROR: syntax error at or near "VARCHAR" Position: 356

基于 PostgreSQL declaration documentation 似乎还可以...

到目前为止我尝试过的:

您不需要 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,它应该可以工作(但同样具有两个嵌套循环的解决方案效率不高)。

感谢@a_horse_with_no_name 的评论指出 $$ LANGUAGE SQL 应该是 $$ LANGUAGE plpgsql 我找到了解决方案。 在我更改为 $$ LANGUAGE plpgsql 后,我收到一个关于缺少 OUT PARAMETER 的新错误,但是 OUT PARAMETER 不允许与 RETURN NEXT 一起使用,所以我不得不 return 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;

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

  • plpgsql error "RETURN NEXT cannot have a parameter in function with OUT parameters" in table-returning function:
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
   <strike>name VARCHAR(12);</strike>  -- 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 查询中可见。一个普遍的约定是在变量名前加上 _ 和 table - 限定查询中的所有列。请参阅今天早些时候的回答:

整个函数可能可以用一个 SELECT 语句代替。