PostgreSQL:错误:42601:函数返回“record”时需要列定义列表

(免责声明:PostgreSQL新手。)

好的,据我所知,我的function与我所见过的样品非常相似。 有人能告诉我如何让这个工作?

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; 

如果你想创build函数返回setoflogging,你需要在你的select语句中定义列types

更多信息

你的查询应该是这样的:

 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) 

(你可能需要改变数据types)

我个人喜欢types的方法。 它确保如果编辑该function,所有的查询将返回正确的结果。 这可能是一个痛苦,因为每次你修改函数的参数,你将需要重新创build/放置types。

例如:

 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; 

返回选定的列

 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; 

呼叫:

 SELECT * FROM get_user_by_username('myuser', TRUE) 

重点

  • 你有DECLARE result record; 但没有使用该variables。 我删除了这个垃圾。

  • 您可以直接从UPDATE返回logging,这要比调用额外的SELECT语句快得多。 用RETURNING子句使用RETURN QUERYUPDATE
    如果用户不是_online ,则默认为普通的SELECT

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

  • 如果users.username在表中被定义为唯一的 ,那么第二个查询中的LIMIT 1就是cruft。
    如果不是 ,那么UPDATE可以更新多行,这很可能是错误的
    我假设一个唯一的username并删除了cruft。

  • 定义函数返回types (就像@ertx演示的那样),或者你将不得不在每个函数调用中提供一个列定义列表,这很尴尬。

  • 为此目的创build一个types(如@ertx提出的)是一个有效的方法,但可能矫枉过正的单一function。 这是在旧版本的PostgreSQL之前,我们有RETURNS TABLE为此目的 – 如上面演示。

  • 这个简单的function不需要循环

  • 每个function都需要一个语言声明。 LANGUAGE plpgsql在这种情况下。

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

返回整个表格

如果你想返回所有的表users ,有一个更简单的方法。 PostgreSQL自动为每个表定义一个同名复合types 。 在这种情况下,您可以使用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; 

如果您需要更多的“dynamic”,请考虑:

  • 重构PL / pgSQL函数以返回各种SELECT查询的输出