PostgreSQL:错误:42601:返回"记录"的函数需要列定义列表

Jer*_*acs 36 postgresql plpgsql

(免责声明:PostgreSQL新手.)

好吧,据我所知,我的功能与我见过的样本非常相似.有人能否告诉我如何让这个工作?

create or replace function get_user_by_username(
    username varchar(250),
    online boolean
    ) returns setof record as $$
declare result record;
begin

    if online then 
        update users
        set last_activity = current_timestamp
        where user_name = username;
    end if;

    return query
    select
        user_id,
        user_name,
        last_activity,
        created,
        email,
        approved,
        last_lockout,
        last_login,
        last_password_changed,
        password_question,
        comment
    from
        users
    where
        user_name = username
    limit 1;

    return;
end;
$$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 41

返回选定的列

CREATE OR REPLACE FUNCTION get_user_by_username(_username text, _online bool)
  RETURNS TABLE (
    user_id int
   ,user_name text
   ,last_activity timestamp
   , ... ) AS
$func$
BEGIN

IF _online THEN
   RETURN QUERY
   UPDATE users u 
   SET    last_activity = current_timestamp
   WHERE  u.user_name = _username
   RETURNING
          u.user_id
         ,u.user_name
         ,u.last_activity
         , ... ;
ELSE
   RETURN QUERY
   SELECT u.user_id
         ,u.user_name
         ,u.last_activity
         , ...
   FROM   users u
   WHERE  u.user_name = _username;
END IF;

END
$func$  LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT * FROM get_user_by_username('myuser', TRUE)
Run Code Online (Sandbox Code Playgroud)

主要观点

  • 你有,DECLARE result record;但没有使用变量.我删除了残骸.

  • 您可以直接从中返回记录UPDATE,这比调用其他SELECT语句要快得多.使用RETURN QUERYUPDATE使用RETURNING条款.
    如果用户不是_online,则默认为普通SELECT.

  • 如果您没有tablename.columnname对函数内的查询中的列名()进行表限定,请注意列名和命名参数之间的命名冲突,这些参数在函数内的任何位置都是可见的(大多数).
    您还可以通过$n对参数使用位置引用()来避免此类冲突.或者使用从不用于列名的前缀:如下划线(_username).

  • 如果在您的表中users.username定义了唯一,那么LIMIT 1在第二个查询中只是愚蠢的.
    如果不是,则UPDATE可以更新多行,这很可能是错误的.
    我假设一个独特的username并删除了残酷.

  • 定义函数返回类型(如@ertx演示)或者您必须在每个函数调用中提供列定义列表,这很尴尬.

  • 为此目的创建类型(如@ertx提议)是一种有效的方法,但对于单个函数可能过度.这是在我们RETURNS TABLE为此目的之前使用旧版PostgreSQL的方法- 如上所示.

  • 并不需要一个循环为这个简单的功能.

  • 每个函数都需要语言声明.LANGUAGE plpgsql在这种情况下.

  • 定义varchar(250)参数的长度限制()可能没有意义.我简化了打字text.

归还整张桌子

如果要返回所有列users,则有一种更简单的方法.PostgreSQL自动为每个表定义同名复合类型.在这种情况下,您可以使用RETURNS SETOF users并大大简化查询:

CREATE OR REPLACE FUNCTION get_user_by_username(_username text, _online bool)
  RETURNS SETOF users AS
$func$
BEGIN

IF _online THEN
    RETURN QUERY
    UPDATE users u 
    SET    last_activity = current_timestamp
    WHERE  u.user_name = _username
    RETURNING u.*;
ELSE
    RETURN QUERY
    SELECT *
    FROM   users u
    WHERE  u.user_name = _username;
END IF;

END
$func$  LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

如果您需要更"动态"的东西,请考虑:

  • 很干净。Ertx 让我找到了一个我可以弄清楚其余部分的地方,但这是一篇出色的文章。我希望它能为其他 PostgreSQL 新手从业者消除一些困惑。 (2认同)

ert*_*rtx 30

如果要创建函数返回setof记录,则需要在select语句中定义列类型

更多信息

您的查询应如下所示:

select * from get_user_by_username('Username', True) as 
  f(user_id integer, user_name varchar, last_activity, varchar, created date, email        archar, approved boolean, last_lockout timestamp, last_login timestamp, 
  last_password_changed timestamp, password_question varchar, comment varchar)
Run Code Online (Sandbox Code Playgroud)

(您可能需要更改数据类型)

我个人更喜欢类型方法.它确保如果编辑该函数,所有查询将返回正确的结果.这可能是一种痛苦,因为每次修改函数的参数时,您都需要重新创建/删除类型.

例如:

CREATE TYPE return_type as 
(user_id integer,
 user_name varchar,
 last_activity varchar,
 created timestamp,
 email varchar,
 approved boolean,
 last_lockout timestamp ,
 last_login timestamp,
 last_password_changed timestamp,
 password_question varchar,
 comment varchar);

create or replace function get_user_by_username( username varchar(250), online 

boolean) returns setof return_type as $$
declare _rec return_type;
begin
    if online then 
        update users
        set last_activity = current_timestamp
        where user_name = username;
    end if;
    for _rec in select
        user_id,
        user_name,
        last_activity,
        created,
        email,
        approved,
        last_lockout,
        last_login,
        last_password_changed,
        password_question,
        comment
      from
        users
      where
        user_name = username
      limit 1 
    loop

      return next _rec;

    end loop

end;
$$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)