(免责声明:PostgreSQL新手。)
好的,据我所知,我的功能与我见过的样本非常相似。有人能否告诉我如何使其发挥作用?
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;
答案 0 :(得分:41)
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;
但未使用该变量。我删除了残骸。
您可以直接从UPDATE
返回记录,这比调用其他SELECT
语句要快得多。使用RETURN QUERY
和UPDATE
with a RETURNING
clause
如果用户不是_online
,则默认为普通SELECT
。
如果您没有在函数内的查询中对列名称(tablename.columnname
)进行表限定,请注意列名和命名参数之间的命名冲突在功能内的任何地方都可见(大多数)
您还可以通过对参数使用位置引用($n
)来避免此类冲突。或者使用从不用于列名称的前缀:如下划线(_username
)。
如果 users.username
在您的表格中定义为唯一,那么第二个查询中的LIMIT 1
就是残缺的。
如果不,则UPDATE
可以更新多行,这很可能错误。
我假设了一个独特的username
并删除了残缺。
定义函数的返回类型(如@ertx演示)或者您必须在每个函数调用中提供列定义列表,这很尴尬。
< / LI>为此目的创建一个类型(如@ertx提议)是一种有效的方法,但对于单个函数可能有点过分。在我们为此目的RETURNS TABLE
之前,这是旧版PostgreSQL的方法 - 如上所示。
不需要循环来完成这个简单的功能。
每个函数都需要语言声明。 LANGUAGE plpgsql
在这种情况下。
为参数定义长度限制(varchar(250)
)可能没有意义。我简化为输入 text
。
如果要返回表users
的所有列,则有一种更简单的方法。 PostgreSQL自动为每个表定义一个同名的复合类型。在这种情况下,您可以使用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;
如果您需要更“动态”的内容,请考虑:
答案 1 :(得分:29)
如果你想创建函数返回setof记录,你需要在select语句中定义列类型
您的查询应如下所示:
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)
(您可能需要更改数据类型)
我个人更喜欢类型方法。它确保如果编辑该函数,所有查询将返回正确的结果。这可能是一种痛苦,因为每次修改函数的参数时,您都需要重新创建/删除类型。
例如:
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;