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 QUERY和UPDATE。
 如果用户不是_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查询的输出