"missing FROM-clause entry" 在 PLPGSQL 函数中更新 table

"missing FROM-clause entry" in PLPGSQL function to update a table

我正在尝试更新 Postgres 中的 table,但出现以下错误。
Userid 是主键。

CREATE OR REPLACE FUNCTION public.update_user(username character varying, 
                                                userid character varying, 
                                                roleid integer,
                                                deptid integer, 
                                                status integer)
RETURNS integer AS 
$$
BEGIN

UPDATE public."M_User" SET public."M_User".user_name = public.update_user.username, 
    public."M_User".user_role_id = public.update_user.roleid, 
    public."M_User".dept_id = public.update_user.deptid, 
    public."M_User".status = public.update_user.status 
    WHERE public."M_User".user_id = userid;
    
RETURN 0;
END
$$
LANGUAGE 'plpgsql';

通话:

SELECT * FROM public.update_user ('ji','gis', 123, 24, 1);

错误:

ERROR:  missing FROM-clause entry for table "update_user"
LINE 1: ...E public."M_User" SET public."M_User".user_name = public.upd...
                                                             ^
QUERY:  UPDATE public."M_User" SET public."M_User".user_name = public.update_user.username, 
  public."M_User".user_role_id = public.update_user.roleid, 
  public."M_User".dept_id = public.update_user.deptid, 
  public."M_User".status = public.update_user.status 
  WHERE public."M_User".user_id = userid
CONTEXT:  PL/pgSQL function update_user(character varying,character varying,integer,integer,integer) line 4 at SQL

statement SQL state: 42P01

如何解决这个问题?

doc 表示可以将输入引用为 function_name.parameter_name,因此请尝试删除对 schema_name

的引用
UPDATE public."M_User" 
SET user_name = update_user.username, 
    user_role_id = update_user.roleid, 
    dept_id = update_user.deptid, 
    status = update_user.status 
WHERE user_id = update_user.userid;
CREATE OR REPLACE FUNCTION public.update_user(_username varchar, 
                                                _userid varchar, 
                                                _roleid integer,
                                                _deptid integer, 
                                                _status integer)
  RETURNS integer
  LANGUAGE sql AS 
$func$
UPDATE public."M_User" u
SET    user_name    = _username
     , user_role_id = _roleid
     , dept_id      = _deptid
     , status       = _status 
WHERE  u.user_id = _userid
AND   (u.user_name, u.user_role_id, u.dept_id, u.status) IS DISTINCT FROM
      ( _username ,       _roleid ,  _deptid ,  _status)  -- optional addition
RETURNING u.user_id;
$func$

可以 使用要消除歧义的函数名称限定函数参数,但这通常是一个笨拙的解决方案。重命名函数时中断。还有其他方法。参见:

  • PL/pgSQL column name the same as variable

我喜欢在参数和变量前加上下划线,而从不对列名做同样的事情。不是标准,而是一个广泛的惯例。养成 table 限定所有列名的习惯,这样就安全了。 table 别名有助于降低噪音。 the manual on UPDATE.

中的基础知识

但是 UPDATE 语句中的目标列无法限定。 (他们从不模棱两可。)

我添加了一个可选的谓词以跳过更新,如果它不会改变任何东西的话。参见:

  • How do I (or can I) SELECT DISTINCT on multiple columns?

您不需要 PL/pgSQL。 (虽然你 可以 ,当然。)一个更简单的 SQL 函数可以完成这项工作。参见:

  • Difference between language sql and language plpgsql in PostgreSQL functions

RETURN 0 没有任何用处。我将其更改为 return 更新行的有效 user_id。 (通常与输入 _userid 相同,但它可能与触发器不同。)重要的区别:如果一行实际更新,您只会获得 return 值,这使其很有用。否则,您不妨将函数声明为 RETURNS void。与无条件 RETURN 0; 一样有用,但更便宜。