我目前正在学习很多PostgreSQL,尤其是PLPGSQL
,并且正在努力处理函数中的查询结果。
我想在用户表周围创建一个包装器,然后使用结果然后返回它。
在我的情况下,用户和帐户是两个不同的表,我想一次创建它。
我的第一个天真的方法是建立以下内容:
CREATE OR REPLACE FUNCTION schema.create_user_with_login (IN email varchar, IN password varchar, IN firstname varchar DEFAULT NULL, IN surname varchar DEFAULT NULL)
RETURNS schema.user
LANGUAGE plpgsql
VOLATILE
RETURNS NULL ON NULL INPUT
AS
$$
declare
created_user schema."user";
begin
INSERT INTO schema."user" ("firstname", "surname", "email")
VALUES (firstname, surname, email)
RETURNING * INTO created_user;
// [...] create accounts and other data using e.g. created_user.id
// the query should return the initially created user
RETURN created_user
end;
$$;
此方法不起作用,因为schema.user
具有NOT NULL
个字段(具有该约束的域类型)并将为声明的语句抛出异常:
domain schema."USER_ID" does not allow null values
所以也许它可以起作用,但不能在那种有限的环境中使用。
我还尝试使用RETURNS SETOF schema.user
并直接使用RETURN QUERY INSERT ....
,但这不会返回所有列,而是返回包含所有数据的列。
如何在函数内部提供数据的同时,实现将初始用户对象作为正确的用户行返回的效果?
我正在使用Postgres 9.6。我的版本输出:
PostgreSQL 9.6.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16), 64-bit
答案 0 :(得分:4)
有几个问题。
我还尝试使用
RETURNS SETOF schema.user
并直接使用RETURN QUERY INSERT
....,但这不会返回所有列,而是 一列包含所有数据。
确定它会返回所有列。您必须 调用 设置返回函数,如下所示:
SELECT * FROM schema.create_user_with_login;
您必须将其声明为RETURNS SETOF foo.users
才能与RETURN QUERY
合作。
将函数声明为STRICT
(RETURNS NULL ON NULL INPUT
的同义词)然后声明NULL参数默认值是无稽之谈:
... firstname varchar DEFAULT NULL, IN surname varchar DEFAULT NULL)
你无法将NULL值传递给定义为STRICT
的函数,它只返回NULL并且什么都不做。虽然firstname
和surname
是可选的,但不定义函数strict(或传递空字符串或其他内容)
请勿调用您的架构"schema"
完全不要使用reserved word user
作为标识符。
尽可能在任何地方使用合法的,小写的,不带引号的标识符。
考虑到所有因素,您的功能可能如下所示:
CREATE OR REPLACE FUNCTION foo.create_user_with_login (_email text
, _password text
, _firstname text = NULL
, _surname text = NULL)
RETURNS SETOF foo.users AS
$func$
begin
RETURN QUERY
WITH u AS (
INSERT INTO foo.users (firstname, surname, email)
VALUES (_firstname, _surname, _email)
RETURNING *
)
, a AS ( -- create account using created_user.id
INSERT INTO accounts (user_id)
SELECT u.user_id FROM u
)
-- more chained CTEs with DML statements?
TABLE u; -- return the initially created user
end
$func$ LANGUAGE plpgsql; -- do *not* define it STRICT
是的,这是一个单个 SQL语句,其中包含几个数据修改CTE来完成所有操作。最快,最干净。为方便起见,函数包装器是可选的。相关:
我在函数参数名称前加下划线(_email
)以排除命名约定。这完全是可选的,但如果不这样做,则必须知道参数,变量和列名称的范围。
TABLE u
是SELECT * FROM u
的缩写。
三个不同的案例: