table/setof 类型的 PostgreSQL 数组

PostgreSQL array of type table/setof

我需要在 postgresql 中编写一个函数,该函数必须根据条件从 table 'pick' 整行,然后将它们插入数组,最后 return 该数组.

我实际上是在查询我需要的行,但是 table 中有一个特殊的列,我必须首先评估它是否可以检索它(插入到数组中),具体取决于正在查询的用户类型(客户或工作人员)。

例如:

特殊列名为“watchers”,有两个变体:'my_team' 和 'only_me',还有一个名为“user_id”的列。

如果该列显示 'my_team',该行可以毫无问题地插入到数组中,但如果显示 'only_me',我必须比较调用该函数的用户的 id 和用户注册在那一行,如果匹配我可以把它插入到数组中,否则我不能。

事情是,正如我到目前为止所读到的那样,它似乎不能用数组来完成,所以我想知道是否有另一种方法可以做到这一点,也许有一个额外的 table 什么的?

感谢您的帮助!

这是我的代码:

CREATE OR REPLACE FUNCTION public.calculates_permission_by_task(task_id integer)
 RETURNS SETOF permission
 LANGUAGE plpgsql
 STABLE
AS $function$
    DECLARE 
        num int := 5;
        record permission;
        ret_permissions permission [];
    BEGIN

        FOR record IN (select
                p.id, p.slug
            from task as t
            join service_request_form as srf on t.service_request_form_id = srf.id
            join service_group as sg on srf.service_group_id = sg.id
            join worker_group as wg on wg.service_group_id = sg.id
            join worker_group_member as wgm on wg.id = wgm.worker_group_id
            join role as r on r.id = wgm.role_id
            join permission_role as pr on r.id = pr.role_id
            join permission as p on p.id = pr.permission_id
            where t.id = task_id
                and wgm.user_id = 'LFudaU6jzid4SKFlU8MgFAwezyP2'
                and pr.value <> 'off'
            and pr.value <> 'no')
        LOOP
            /* Here is where I pretend to do the comparison and insert data into the array */
            ret_permission := array_append(ret_permissions, record.id);
        END LOOP;
        
        RETURN ret_permissions;
        
    END
$function$

您可以在查询本身中实现逻辑。

假设您引用的 user_id 列对应于已在查询中的 wgm.user_id,则查询的 where 子句将变为:

where 
    t.id = task_id
    and pr.value not in ('off', 'no')
    and (
        ?.watchers = 'my_team'
        or (
            ?.watchers = 'only_me'
            or wgm.user_id = 'LFudaU6jzid4SKFlU8MgFAwezyP2'
        )
    )

你不知道 table watches 属于哪个,所以我使用了 ?,你需要将其替换为相关的 table 别名。

如果 watchers 只有两个可能的值,那么我们可以简化谓词:

where 
    t.id = task_id
    and pr.value not in ('off', 'no')
    and (?.watchers = 'my_team' or wgm.user_id = 'LFudaU6jzid4SKFlU8MgFAwezyP2')
  • 你不需要数组
  • 你不需要游标循环
  • 你甚至不需要 plpgsql
  • 普通 SQL 就足够了:

CREATE TABLE  permission (
         id integer
        , slug text
        );
INSERT INTO permission(id,slug) VALUES (1,'WTF' );
CREATE TABLE  task (
        id  integer
        , service_request_form_id  integer
        );
INSERT INTO task(id, service_request_form_id) VALUES (1,1 );
CREATE TABLE  service_request_form (
        id integer
        , service_group_id  integer
        );
INSERT INTO service_request_form(id, service_group_id) VALUES (1,1 );
CREATE TABLE  service_group (
        id integer
        );
INSERT INTO service_group(id) VALUES (1);
CREATE TABLE  worker_group (
        id  integer
        , service_group_id  integer
        );
INSERT INTO worker_group(id, service_group_id) VALUES (1,1 );
CREATE TABLE  worker_group_member (
        worker_group_id integer
        , role_id integer
        , user_id text
        );
INSERT INTO worker_group_member(worker_group_id, role_id,user_id) VALUES (1,1,'LFudaU6jzid4SKFlU8MgFAwezyP2' );
CREATE TABLE  zrole (
        id  integer
        );
INSERT INTO zrole(id) VALUES (1 );
CREATE TABLE  permission_role (
        role_id integer
        , permission_id integer
        , value text
        );
INSERT INTO permission_role(role_id,permission_id,value) VALUES (1,1,'Yes' );

CREATE OR REPLACE FUNCTION public.calculates_permission_by_task(task_id integer)
 RETURNS SETOF permission
 LANGUAGE sql STABLE SECURITY INVOKER ROWS 30 -- COST 1
AS $func$

        SELECT p.id, p.slug
        FROM permission as p
        WHERE EXISTS (
                SELECT *
                FROM task as t
                JOIN service_request_form as srf
                         on t.service_request_form_id = srf.id
                JOIN service_group as sg
                        on srf.service_group_id = sg.id
                JOIN worker_group as wg
                        on wg.service_group_id = sg.id
                JOIN worker_group_member as wgm
                        on wg.id = wgm.worker_group_id
                JOIN zrole as zr
                        on zr.id = wgm.role_id
                JOIN permission_role as pr
                        on zr.id = pr.role_id
                WHERE p.id = pr.permission_id
                AND t.id = task_id
                and wgm.user_id = 'LFudaU6jzid4SKFlU8MgFAwezyP2'
                and pr.value NOT IN( 'off' , 'no' )
                -- -------------------------
                -- Add the needed logic
                -- (From @GMB) here
                -- -------------------------
                );
$func$
        ;


    -- Usage:
    -- --------------
SELECT * -- p.id, p.slug
FROM public.calculates_permission_by_task(42);