返回选定的列
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
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
和带有RETURNING
子句的UPDATE
。
如果用户不是_online
,则默认使用普通的SELECT
。如果省略第二个参数,则也是(安全的)默认值 - 在函数定义中提供了DEFAULT false
后才可能发生。
如果在函数内部的查询中不为列名加上表限定符(tablename.columnname
),则要注意列名与命名参数之间的名称冲突,它们(大多数情况下)在函数内部的任何地方都可见。
你还可以通过使用参数的位置引用($n
)来避免这种冲突。或者使用一个前缀,你从未用于列名:比如下划线(_username
)。
如果您的表中定义了users.username
唯一,那么第二个查询中的LIMIT 1
只是多余的。如果它不是,则UPDATE
可以更新多行,这很可能是错误的。我假设username
是唯一的并删去了无用内容。
定义函数的返回类型(如 @ertx所示),否则您必须在每个函数调用中提供一个列定义列表,这很麻烦。
为此创建一个类型(如@ertx建议的)是一个有效的方法,但对于单个函数来说可能有点过度设计。在 Postgres 在拥有RETURNS TABLE
之前,这是正确的方式 - 正如上面所示。
这个简单的函数不需要循环。
每个函数都需要语言声明。在这种情况下是LANGUAGE plpgsql
。
我使用timestamptz
(带时区的时间戳)而不是timestamp
(不带时区的时间戳),这是明智的默认值。请参见:
返回(一组)完整的行
要返回现有表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
WHERE u.user_name = _username
RETURNING u
, 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 在这里(显示所有)
如果您需要更加“动态”的内容,请考虑: