类型为table / setof的PostgreSQL数组

问题描述

我需要在postgresql中编写一个函数,该函数必须根据条件从表中“拾取”整个行,然后将它们插入到数组中,最后返回该数组。

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

例如:

该特殊列名为“观察者”,具有两个变体:“ my_team”和“ only_me”,还具有另一个名为“ user_id”的列。

如果该列显示为“ my_team”,则可以毫无问题地将该行插入阵列,但是如果显示为“ only_me”,则必须比较调用函数用户和在该行中注册用户的ID它们匹配,我可以将其插入数组,否则不能。

事情是,到目前为止,我似乎无法用数组完成它,所以我想知道是否还有另一种方法,也许可以使用额外的表或其他东西? >

感谢您的帮助!

这是我的代码

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'
        )
    )

您不知道watches属于哪个表,所以我使用了?,您需要用相关的表别名替换它。

如果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,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,'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);