pl/pgsql 函数中的动态 SQL 语法错误
Syntax error in dynamic SQL in pl/pgsql function
我在 PostgreSQL 10 中使用 pl/pgsql 来创建复杂查询。我正在用几个 JOIN
s 和 AND
s 测试一个查询。这是我目前所拥有的:
DROP FUNCTION IF EXISTS search_person(name text);
CREATE FUNCTION search_person(name text) RETURNS TABLE(address_id integer, address_geom text, event_name text) AS $$
--DECLARE
BEGIN
RETURN QUERY EXECUTE
'SELECT address.id, event.name, address.geom
FROM event JOIN person JOIN address JOIN person_address JOIN event_person
WHERE
person_address.event_id = event.id AND
event_person.event_id = event.id AND
person.id = event_person.person_id AND
person.name like
'
USING name;
END;
$$
LANGUAGE plpgsql;
我在创建这个函数时没有遇到任何错误。我这样称呼它 select search_person('nick');
我得到:
ERROR: syntax error at or near "WHERE"
LINE 3: WHERE
^
QUERY: SELECT address.id, event.name, address.geom
FROM event JOIN person JOIN address JOIN person_address JOIN event_person
WHERE
person_address.event_id = event.id AND
event_person.event_id = event.id AND
person.id = event_person.person_id AND
person.name like
CONTEXT: PL/pgSQL function search_creator(text) line 5 at RETURN QUERY
SQL state: 42601
我看不到或无法解决问题。我尝试在 WHERE
子句中将 AND
替换为 ||
,但没有任何改变。
我该怎么办?
编辑
这是我现在的代码,但根据我检查的数据库数据,我得到了一个空的 table,尽管我应该得到结果。
CREATE FUNCTION search_person(name character(600)) RETURNS TABLE(address_id bigint, address_geom geometry, event_name character(200)) AS $$
BEGIN
RETURN QUERY EXECUTE
'SELECT address.id, address.geom, event.name
FROM
person
JOIN event_creator ON event_person.person_id = person.id
JOIN event ON event.id = event_person.event_id
JOIN person_address ON person_address.event_id = event.id
JOIN address ON address.id = cep.address_id
WHERE person.name LIKE '
USING name;
END;
$$
LANGUAGE plpgsql;
创建 PL/pgSQL 函数时,函数体按原样 保存为字符串文字 。仅应用表面语法检查。包含的语句实际上并未在更深层次上执行或测试。
但是,在实际的 SQL 语句中仍会检测到查询字符串中的基本语法错误。但是你正在使用 dynamic SQL with EXECUTE
。该语句包含在嵌套的字符串文字中,您自己负责。
这似乎从一开始就被误导了。动态 SQL 没有明显的原因。 (除非你的数据分布非常不均匀,并且想强制 Postgres 为每个输入值生成自定义计划。)
如果您使用了普通的 SQL 语句,您会在创建时收到错误消息:
CREATE OR REPLACE FUNCTION search_person(name text) -- still incorrect!
RETURNS TABLE(address_id integer, address_geom text, event_name text) AS
$func$
BEGIN
RETURN QUERY
SELECT address.id, event.name, address.geom
FROM event JOIN person JOIN address JOIN person_address JOIN event_person
WHERE
person_address.event_id = event.id AND
event_person.event_id = event.id AND
person.id = event_person.person_id AND
person.name like ; -- still , but refers to func param now!
END
$func$ LANGUAGE plpgsql;
SQL 语句仍然无效。 [INNER] JOIN
requires a join condition - 。而且我根本看不到 PL/pgSQL 的必要性。一个简单的 SQL 函数 应该很好用:
CREATE FUNCTION search_person(name text)
RETURNS TABLE(address_id integer, address_geom text, event_name text) AS
$func$
SELECT a.id, a.geom, e.name -- also fixed column order to match return type
FROM person AS p
JOIN event_person AS ep ON ep.person_id = p.id
JOIN event AS e ON e.id = ep.event_id
JOIN person_address AS pa ON pa.event_id = e.id
JOIN address AS a ON a.id = pa.address_id -- missing join condition !!
WHERE p.name LIKE ;
$func$ LANGUAGE sql;
我重写了查询以修复语法错误,使用 table 别名以提高可读性。最后,我还根据有根据的猜测添加了一个缺失的条件:a.id = pa.address_id
.
现在应该可以了。
相关:
- plpgsql function not inserting data as intended
- Difference between language sql and language plpgsql in PostgreSQL functions
或者根本没有任何功能,只需使用准备好的语句代替。示例:
如果您毕竟需要动态 SQL,请像之前那样使用 USING
子句传递 values,并确保防御 SQL 在 连接 查询时注入。 Postgres 提供各种工具:
- SQL injection in Postgres functions vs prepared queries
- Define table and column names as arguments in a plpgsql function?
- Table name as a PostgreSQL function parameter
我在 PostgreSQL 10 中使用 pl/pgsql 来创建复杂查询。我正在用几个 JOIN
s 和 AND
s 测试一个查询。这是我目前所拥有的:
DROP FUNCTION IF EXISTS search_person(name text);
CREATE FUNCTION search_person(name text) RETURNS TABLE(address_id integer, address_geom text, event_name text) AS $$
--DECLARE
BEGIN
RETURN QUERY EXECUTE
'SELECT address.id, event.name, address.geom
FROM event JOIN person JOIN address JOIN person_address JOIN event_person
WHERE
person_address.event_id = event.id AND
event_person.event_id = event.id AND
person.id = event_person.person_id AND
person.name like
'
USING name;
END;
$$
LANGUAGE plpgsql;
我在创建这个函数时没有遇到任何错误。我这样称呼它 select search_person('nick');
我得到:
ERROR: syntax error at or near "WHERE" LINE 3: WHERE ^ QUERY: SELECT address.id, event.name, address.geom FROM event JOIN person JOIN address JOIN person_address JOIN event_person WHERE person_address.event_id = event.id AND event_person.event_id = event.id AND person.id = event_person.person_id AND person.name like CONTEXT: PL/pgSQL function search_creator(text) line 5 at RETURN QUERY SQL state: 42601
我看不到或无法解决问题。我尝试在 WHERE
子句中将 AND
替换为 ||
,但没有任何改变。
我该怎么办?
编辑
这是我现在的代码,但根据我检查的数据库数据,我得到了一个空的 table,尽管我应该得到结果。
CREATE FUNCTION search_person(name character(600)) RETURNS TABLE(address_id bigint, address_geom geometry, event_name character(200)) AS $$
BEGIN
RETURN QUERY EXECUTE
'SELECT address.id, address.geom, event.name
FROM
person
JOIN event_creator ON event_person.person_id = person.id
JOIN event ON event.id = event_person.event_id
JOIN person_address ON person_address.event_id = event.id
JOIN address ON address.id = cep.address_id
WHERE person.name LIKE '
USING name;
END;
$$
LANGUAGE plpgsql;
创建 PL/pgSQL 函数时,函数体按原样 保存为字符串文字 。仅应用表面语法检查。包含的语句实际上并未在更深层次上执行或测试。
但是,在实际的 SQL 语句中仍会检测到查询字符串中的基本语法错误。但是你正在使用 dynamic SQL with EXECUTE
。该语句包含在嵌套的字符串文字中,您自己负责。
这似乎从一开始就被误导了。动态 SQL 没有明显的原因。 (除非你的数据分布非常不均匀,并且想强制 Postgres 为每个输入值生成自定义计划。)
如果您使用了普通的 SQL 语句,您会在创建时收到错误消息:
CREATE OR REPLACE FUNCTION search_person(name text) -- still incorrect!
RETURNS TABLE(address_id integer, address_geom text, event_name text) AS
$func$
BEGIN
RETURN QUERY
SELECT address.id, event.name, address.geom
FROM event JOIN person JOIN address JOIN person_address JOIN event_person
WHERE
person_address.event_id = event.id AND
event_person.event_id = event.id AND
person.id = event_person.person_id AND
person.name like ; -- still , but refers to func param now!
END
$func$ LANGUAGE plpgsql;
SQL 语句仍然无效。 [INNER] JOIN
requires a join condition -
CREATE FUNCTION search_person(name text)
RETURNS TABLE(address_id integer, address_geom text, event_name text) AS
$func$
SELECT a.id, a.geom, e.name -- also fixed column order to match return type
FROM person AS p
JOIN event_person AS ep ON ep.person_id = p.id
JOIN event AS e ON e.id = ep.event_id
JOIN person_address AS pa ON pa.event_id = e.id
JOIN address AS a ON a.id = pa.address_id -- missing join condition !!
WHERE p.name LIKE ;
$func$ LANGUAGE sql;
我重写了查询以修复语法错误,使用 table 别名以提高可读性。最后,我还根据有根据的猜测添加了一个缺失的条件:a.id = pa.address_id
.
现在应该可以了。
相关:
- plpgsql function not inserting data as intended
- Difference between language sql and language plpgsql in PostgreSQL functions
或者根本没有任何功能,只需使用准备好的语句代替。示例:
如果您毕竟需要动态 SQL,请像之前那样使用 USING
子句传递 values,并确保防御 SQL 在 连接 查询时注入。 Postgres 提供各种工具:
- SQL injection in Postgres functions vs prepared queries
- Define table and column names as arguments in a plpgsql function?
- Table name as a PostgreSQL function parameter