'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 似乎还可以...
到目前为止我尝试过的:
我把name VARCHAR(12);
改成了name location.mac%TYPE
我把name VARCHAR(12);
改成了name RECORD
我改变了声明的范围然后我在 poly_id INTEGER;
上得到了同样的错误
我把LANGUAGE SQL
改成了postgressql
我用谷歌搜索了一下,根据 example/problem 我发现这个程序应该有效。
您不需要 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
语句代替。
我创建了以下存储过程,它应该 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 似乎还可以...
到目前为止我尝试过的:
我把
name VARCHAR(12);
改成了name location.mac%TYPE
我把
name VARCHAR(12);
改成了name RECORD
我改变了声明的范围然后我在
poly_id INTEGER;
上得到了同样的错误
我把
LANGUAGE SQL
改成了postgressql
我用谷歌搜索了一下,根据 example/problem 我发现这个程序应该有效。
您不需要 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
语句代替。