0

我有一个带有表的数据库,这些表维护有关用户和其他用户的信息,这些用户可以批准这些用户的任务。该审批者可以是用户的主管(维护在表的一对多关系中users),或者是另一个明确授予审批权限的用户(维护在单独的多对多关系表中)。

我的目标是为给定用户(即,允许该用户批准的人,以及这些批准者的批准链中的任何人)找到完整的“批准者”树(或链)。WHERE u1.username = u2.supervisor由于上面描述的“显式其他批准者”的多对多关系,这不像查找那么简单,所以这不像这里给出的示例那么简单: https ://www.postgresqltutorial.com/postgresql -递归查询/

对于非递归的情况,我编写了一个函数,允许我让所有用户被某个用户批准,看起来像这样(它还做了一些其他的事情,比如根据保存的信息格式化结果另一个表,但它的核心位是子查询中两侧的东西union):

CREATE OR REPLACE FUNCTION public.get_user_approvees(username text)
 RETURNS TABLE(approvee_username text, approvee_name text, approver_username text)
 LANGUAGE plpgsql
AS $function$
#variable_conflict use_variable
    BEGIN
        return query
--          with the below subquery, select the username and get names from preferences for
--          the approvee
            select sq.approvee, up.first_name || ' ' || up.last_name, username as "name" from
            (
--              get the approvees of the users group as a subquery
                select u2.username as approvee from group_approvers ga
                inner join users u2 on u2.group_id = ga.group_id
                where ga.approver = username
                and u2.username != username
                and u2.is_active 
                union 
--              add any other users this user is directly responsible for
                select ua.approvee from user_approvers ua
                inner join users u on u.username = ua.approvee 
                where ua.approver = username
                and u.is_active 
            ) as sq
            inner join users u on sq.approvee = u.username
            inner join user_preferences up on u.user_prefs = up.id; 
    END;
$function$
;

我认为基于此,我应该能够非常简单地编写一个执行相同操作但递归的函数。但是我的尝试不起作用,我想知道(1)为什么?(2) 我怎样才能做到这一点?

这是我对递归 CTE 函数的尝试:

CREATE OR REPLACE FUNCTION public.recursive_test(username text)
RETURNS TABLE(approvee_username text, approvee_name text, approver_name text)
LANGUAGE plpgsql
AS $function$
#variable_conflict use_variable
    BEGIN
        return query
            WITH RECURSIVE all_approvees AS (
                    (
                        SELECT * FROM get_user_approvees(username) 
                    )
                    UNION 
                    (
                        SELECT * FROM get_user_approvees(all_approvees.approvee)
                    )
            ) SELECT 
                *
            FROM all_approvees;
    END;
$function$
;

当我尝试运行此函数时,我在运行时收到一条错误消息:

ERROR:  missing FROM-clause entry for table "all_approvees"
LINE 7:       SELECT * FROM get_user_approvees(all_approvees.approve...

有什么想法吗?

4

1 回答 1

1

这可能无法解决您的所有问题,但您收到该错误仅仅是因为您在FROM查询的递归部分的子句中没有递归表。它应该看起来像这样 -

WITH RECURSIVE all_approvees (approvee, name) AS (
    SELECT * FROM get_user_approvees(username) 
    UNION 
    SELECT f.* FROM all_approvees, get_user_approvees(all_approvees.approvee) as f
) 
SELECT *
FROM all_approvees;
于 2021-01-09T07:38:17.827 回答