返回选定的列
CREATE OR REPLACE FUNCTION get_user_by_username(_username text
, _online bool DEFAULT false)
RETURNS TABLE (
user_id int
, user_name varchar
, last_activity timestamptz
)
LANGUAGE plpgsql AS
$func$
BEGIN
IF _online THEN
RETURN QUERY
UPDATE users u
SET last_activity = current_timestamp -- ts with time zone
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$;
称呼:
SELECT * FROM get_user_by_username('myuser', true);
您有DECLARE result record;
但没有使用该变量。我删除了杂物。
您可以直接从 中返回记录,这比调用附加语句UPDATE
要快得多。SELECT
使用RETURN QUERY
and UPDATE
withRETURNING
子句。
如果用户不是_online
,则默认为普通的SELECT
。如果省略第二个参数,这也是(安全)默认值 - 只有DEFAULT false
在函数定义中提供该默认值后才有可能。
如果您tablename.columnname
在函数内部的查询中没有对列名 ( ) 进行表限定,请注意列名和命名参数之间的命名冲突,这些冲突在函数内的任何地方(大多数)都是可见的。
您还可以通过$n
对参数使用位置引用 ( ) 来避免此类冲突。或者使用您从不用于列名的前缀:例如下划线 ( _username
)。
如果在您的表users.username
中定义为唯一LIMIT 1
的,那么在第二个查询中只是简单的。如果不是,则UPDATE
可以更新多行,这很可能是错误的。我假设一个独特的username
并修剪噪音。
定义函数的返回类型(就像@ertx 演示的那样),或者您必须为每个函数调用提供一个列定义列表,这很尴尬。
为此目的创建一个类型(如@ertx 提议的)是一种有效的方法,但对于单个函数来说可能是矫枉过正。这是在我们RETURNS TABLE
为此目的之前在旧版本的 Postgres 中使用的方法——如上所示。
这个简单的函数不需要循环。
每个函数都需要一个语言声明。LANGUAGE plpgsql
在这种情况下。
我使用timestamptz
( timestamp with time zone
) 而不是timestamp
( timestamp without time zone
),这是正常的默认设置。看:
返回(组)整行
要返回现有表的所有列users
,有一种更简单的方法。Postgres 自动为每个表定义一个同名的复合类型。只需用于RETURNS SETOF users
大大简化查询:
CREATE OR REPLACE FUNCTION get_user_by_username(_username text
, _online bool DEFAULT false)
RETURNS SETOF users
LANGUAGE plpgsql 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$;
返回整行加上自定义添加
要解决 TheRealChx101 在下面的评论中添加的问题:
如果除了整个表之外还有一个计算值怎么办?
没有那么简单,但可行。我们可以将整个行类型作为一个字段发送,并添加更多:
CREATE OR REPLACE FUNCTION get_user_by_username3(_username text
, _online bool DEFAULT false)
RETURNS TABLE (
users_row users
, custom_addition text
)
LANGUAGE plpgsql AS
$func$
BEGIN
IF _online THEN
RETURN QUERY
UPDATE users u
SET last_activity = current_timestamp -- ts with time zone
WHERE u.user_name = _username
RETURNING u -- whole row
, u.user_name || u.user_id;
ELSE
RETURN QUERY
SELECT u, u.user_name || u.user_id
FROM users u
WHERE u.user_name = _username;
END IF;
END
$func$;
“魔法”在函数调用中,我们(可选地)分解行类型:
SELECT (users_row).*, custom_addition FROM get_user_by_username('foo', true);
db<>fiddle here(显示全部)
如果您需要更“动态”的东西,请考虑: