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查询的输出