简体   繁体   English

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

[英]Syntax error in dynamic SQL in pl/pgsql function

I am using pl/pgsql in PostgreSQL 10, to create complex queries. 我在PostgreSQL 10中使用pl / pgsql创建复杂的查询。 I am testing a query with a couple of JOIN s and AND s. 我正在测试几个JOINAND的查询。 This is what I have so far: 这是我到目前为止的内容:

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;

I get no errors while creating this function. 创建此函数时没有错误。 I call it like so select search_person('nick'); 我这样称呼,所以select search_person('nick'); and I get: 我得到:

 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 

I cannot see or fix the problem. 我看不到或解决问题。 I tried replacing AND with || 我尝试用||代替AND in the WHERE clause, but nothing changed. WHERE子句中,但没有任何变化。

What should I do? 我该怎么办?

EDIT 编辑

This is the code I have now and I get an empty table, even though I should get results, according to my database data that I checked. 这是我现在拥有的代码,根据我检查的数据库数据,即使应该得到结果,我也会得到一个空表。

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;

When creating a PL/pgSQL function, the function body is saved as string literal as is . 当创建一个PL / pgSQL函数,函数体被保存为字符串字面原样 Only superficial syntax checks are applied. 仅应用表面语法检查。 Contained statements are not actually executed or tested on a deeper level. 所包含的语句实际上并未在更深层次上执行或测试。

However , basic syntax errors like you have in your query string would still be detected in actual SQL statements. 但是 ,在实际的SQL语句中仍会检测到查询字符串中的基本语法错误(如您在查询字符串中一样)。 But you are using dynamic SQL with EXECUTE . 但是您将动态SQL与EXECUTE一起使用。 The statement is contained in a nested string literal and is your responsibility alone. 该语句包含在嵌套字符串文字中,仅由您自己负责。

This seems to be misguided to begin with. 首先,这似乎被误导了。 There is no apparent reason for dynamic SQL. 没有动态SQL的明显原因。 (Unless you have very uneven data distribution and want to force Postgres to generate a custom plan for each input value.) (除非您的数据分布非常不均匀,并且要强制Postgres为每个输入值生成一个自定义计划。)

If you had used a plain SQL statement, you would have gotten the error message at creation time: 如果使用简单的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;

The SQL statement is still invalid. SQL语句仍然无效。 [INNER] JOIN requires a join condition - like Nick commented . [INNER] JOIN 需要一个加入条件, 例如Nick评论 And I don't see the need for PL/pgSQL at all. 而且我完全看不到需要PL / pgSQL。 A simple SQL function should serve well: 一个简单的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;

I rewrote the query to fix syntax error, using table aliases for better readability. 我使用表别名重写查询以修复语法错误,以提高可读性。 Finally, I also added one more missing condition based on an educated guess: a.id = pa.address_id . 最后,我还根据有根据的猜测又添加了一个失踪条件: a.id = pa.address_id

Now it should work. 现在应该可以了。

Related: 有关:

Or no function at all, just use a prepared statement instead. 或根本没有功能,只需使用准备好的语句即可 Example: 例:

If you need dynamic SQL after all, pass values with the USING clause like you had it and make sure to defend against SQL injection when concatenating queries. 如果您毕竟需要动态SQL,则像您一样USING子句传递 ,并确保在连接查询时防止SQL注入。 Postgres provides various tools: Postgres提供了各种工具:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM