Postgresql - 从 plpgsql 函数返回记录 []

Posted

技术标签:

【中文标题】Postgresql - 从 plpgsql 函数返回记录 []【英文标题】:Postgresql - return a record[] from a plpgsql function 【发布时间】:2021-11-22 00:09:29 【问题描述】:

我有一个employer 和一个employee 表。我有一个连接它们的连接表。

CREATE TABLE employer (id int primary key, name text);
CREATE TABLE employee (id int primary key, name text);
CREATE TABLE employer_employee_join(
    employer_id int REFERENCES employer(id),
    employee_id int REFERENCES employee(id)
);

INSERT INTO employer (id, name) VALUES (1, 'the boss');
INSERT INTO employee (id, name) VALUES (1, 'employee1');
INSERT INTO employee (id, name) VALUES (2, 'employee2');

INSERT INTO employer_employee_join (employer_id, employee_id) VALUES(1, 1);
INSERT INTO employer_employee_join (employer_id, employee_id) VALUES(1, 2);

我的 sql 查询返回 employer 并聚合 employee 返回一个记录数组 (record[])。

SELECT 
employer.id, employer.name, array_agg((employee.id, employee.name))
FROM employer
LEFT JOIN employer_employee_join
ON employer_employee_join.employer_id = employer.id
LEFT JOIN employee
ON employee.id = employer_employee_join.employee_id
GROUP BY employer.id;

这很好用。

但是当我把它放在一个 PL/PGSQL 函数中时它失败了:

CREATE OR REPLACE FUNCTION _test()
    RETURNS table(id integer, name text, agg record[]) 
    LANGUAGE 'plpgsql'
AS $BODY$
begin
    SELECT 
    employer.id, employer.name, array_agg((employee.id, employee.name))
    FROM employer
    LEFT JOIN employer_employee_join
    ON employer_employee_join.employer_id = employer.id
    LEFT JOIN employee
    ON employee.id = employer_employee_join.employee_id
    GROUP BY employer.id;
end;
$BODY$

错误是

ERROR:  PL/pgSQL functions cannot accept type record[]
SQL state: 0A000

如何让 plpgsql 函数返回记录数组?

(我真的不想使用json_agg(),因为系统中的另一层不在postgresql和我的控制范围内)

【问题讨论】:

您真正想要的是(int, text) tuple,而不是任意的record。事实上你已经有了那个类型的名字,所以你可以写employee[] "我的 sql 查询返回雇主并汇总雇员" - 你为什么要这样做? “我真的不想使用json_agg(),因为我的系统中有另一层” - 什么是“另一层”,它如何处理 postgres 记录数组,而不是结构化和简单可解析的 json ? 谢谢,Bergi。 employee[] 是我要找的。但是当我只想返回一个表的一个子部分时,我可以返回一个元组数组吗? (另一层在 postgresql 之外。) 如果您只需要选择的列,您可以为此定义一个自定义复合类型。请参阅我链接的文档。 啊,我终于到了。感谢您的帮助。 【参考方案1】:

感谢@Bergi。这是我需要的composite type。

create type employee_agg as (id int, name text);

CREATE OR REPLACE FUNCTION _test()
    RETURNS table(id integer, name text, agg employee_agg[]) 
    LANGUAGE plpgsql
AS $BODY$
begin
    return query
    SELECT 
    employer.id, 
    employer.name, 
    array_agg(row(employee.id, employee.name)::employee_agg)
    FROM employer
    LEFT JOIN employer_employee_join
    ON employer_employee_join.employer_id = employer.id
    LEFT JOIN employee
    ON employee.id = employer_employee_join.employee_id
    GROUP BY employer.id;
end;
$BODY$;

【讨论】:

别那样做……用 SQL 吧……【参考方案2】:

使用视图

就这样吧……

CREATE VIEW _test
AS
    SELECT 
    employer.id, 
    employer.name, 
    array_agg(row(employee.id, employee.name)::employee_agg)
    FROM employer
    LEFT JOIN employer_employee_join
    ON employer_employee_join.employer_id = employer.id
    LEFT JOIN employee
    ON employee.id = employer_employee_join.employee_id
    GROUP BY employer.id;

你的函数没有参数,它只是一个查询。这是一个更好的主意。

或者,您可以使用SQL 函数(但视图更好)。

【讨论】:

悲哀一定是个函数。 @mmm111mmm 然后使用 SQL。它的工作原理相同,但速度会更快。

以上是关于Postgresql - 从 plpgsql 函数返回记录 []的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL:在 plpgsql 函数中回滚事务?

尝试使用 RETURNING 和更新/插入从 plpgsql 函数返回时出错

PostgreSQL plpgsql 获取当前程序 oid

PostgreSQL - 继续 unique_violation (plpgsql)

Postgresql 10 plpgsql 测试列是不是存在于记录变量中

在 plpgsql(PostgreSQL 的)中,可以将 CTE 保留到外循环吗?