尝试创建函数时,DECLARE部分中“VARCHAR”处或附近的语法错误

时间:2015-12-15 11:58:53

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

我创建了以下存储过程,它应该返回与多边形组交叉的所有位置名称(没有明显的...与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

  • 我用Google搜索,根据任何示例/问题,我发现此程序应该有效。

3 个答案:

答案 0 :(得分: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,它应该可以正常工作(但是,具有两个嵌套循环的解决方案效率不高)。

答案 1 :(得分:1)

感谢@ a_horse_with_no_name的评论指出我$$ LANGUAGE SQL应该是$$ LANGUAGE plpgsql我找到了解决方案。 在我更改为$$ LANGUAGE plpgsql后,我收到了关于丢失OUT PARAMETER的新错误,但OUT PARAMETER不允许RETURN NEXT,因此我不得不返回SETOF而不是TABLE {1}}:

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;

答案 2 :(得分:1)

你提出的答案仍有几个问题。你可以很好地使用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语句替换。