Mad*_*dis 4 postgresql plpgsql sql-returning set-returning-functions
我目前正在学习很多 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;
$$;
Run Code Online (Sandbox Code Playgroud)
这种方法不起作用,因为schema.user具有NOT NULL字段(具有该约束的域类型)并且将为声明的语句抛出异常:
domain schema."USER_ID" does not allow null values
Run Code Online (Sandbox Code Playgroud)
所以也许它可以工作,但不能在那个受限的环境中使用。
我也尝试RETURNS SETOF schema.user直接使用and 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
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 10
我也尝试
RETURNS SETOF schema.user直接使用和RETURN QUERY INSERT....,但这不会返回所有列,而是返回包含所有数据的一列。
当然它返回所有列。您必须像这样调用设置返回函数:
SELECT * FROM schema.create_user_with_login;Run Code Online (Sandbox Code Playgroud)
您必须将其声明为RETURNS SETOF foo.users与 合作RETURN QUERY。
将您的函数声明为STRICT(同义词 for RETURNS NULL ON NULL INPUT)然后声明 NULL 参数默认值是无稽之谈:
... firstname varchar DEFAULT NULL, IN surname varchar DEFAULT NULL)
Run Code Online (Sandbox Code Playgroud)
您不能将 NULL 值传递给定义的函数STRICT,它只会返回 NULL 而什么都不做。虽然firstname和surname是可选的,但不要定义严格的函数(或传递空字符串或其他东西)
不要调用你的 schema "schema"。
根本不要使用保留字 user作为标识符。如果可能,请在任何地方使用合法的、小写的、不带引号的标识符。
考虑到所有因素,您的函数可能如下所示:
CREATE OR REPLACE FUNCTION foo.create_user_with_login (_email text
, _password text
, _firstname text = NULL
, _surname text = NULL)
RETURNS SETOF foo.users
LANGUAGE plpgsql AS -- do *not* define it STRICT
$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$;
Run Code Online (Sandbox Code Playgroud)
是的,这是一个带有多个数据修改 CTE的单个SQL 语句来完成所有操作。最快最干净。为方便起见,函数包装器是可选的。也可能是LANGUAGE sql。有关的:
我在函数参数名称前加上下划线 ( _email) 以排除命名约定。这完全是可选的,但如果不这样做,您必须仔细跟踪冲突参数、变量和列名的范围。
TABLE u是 的缩写SELECT * FROM u。
三种不同的情况:
单值:
单排
行集(= 表)
没有“表变量”,但有其他几个选项:
| 归档时间: |
|
| 查看次数: |
4373 次 |
| 最近记录: |