pl / pgsql函数中动态SQL中的语法错误

时间:2018-01-21 22:27:26

标签: sql postgresql where plpgsql dynamic-sql

我在PostgreSQL 10中使用pl / pgsql来创建复杂的查询。我正在使用几个JOINAND来测试查询。这就是我到目前为止所做的:

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
    $1'        

    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
    $1
CONTEXT:  PL/pgSQL function search_creator(text) line 5 at RETURN QUERY
SQL state: 42601

我无法看到或解决问题。我尝试在AND子句中将||替换为WHERE,但没有任何更改。

我该怎么办?

修改

这是我现在的代码,我得到一个空表,即使我应该得到结果,根据我检查的数据库数据。

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 $1'
    USING name;

END;
$$
LANGUAGE plpgsql;

1 个答案:

答案 0 :(得分:2)

创建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 $1;  -- still $1, but refers to func param now!
END
$func$  LANGUAGE plpgsql;

SQL语句仍然无效。 [INNER] JOIN 要求加入条件 - like Nick commented。我根本不认为需要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 $1;
$func$  LANGUAGE sql;

我重写了查询来修复语法错误,使用表别名来提高可读性。最后,我还根据有根据的猜测添加了一个缺失的条件:a.id = pa.address_id

现在应该可以了。

相关:

或根本没有功能,只需使用预备声明。例如:

如果您需要动态SQL,请使用USING子句传递 values ,并确保在连接查询时防止SQL注入。 Postgres提供了各种工具: