编写调用函数的递归 SQL 查询 (postgreSQL)
Writing recursive SQL query that calls function (postgreSQL)
我有一个包含 table 的数据库,用于维护有关用户和其他用户的信息,这些用户可以为这些用户批准任务。这个审批人可以是用户的主管(维护在users
table的一对多关系中),或者是另一个明确赋予审批权的用户(维护在单独的多对多关系[=32]中) =]).
我的目标是找到给定用户的完整“批准”树(或链)(即允许该用户批准的人,以及这些批准者的批准链中的任何人)。由于上面描述的“显式其他批准者”的多对多关系,这不像查找 WHERE u1.username = u2.supervisor
那么简单,这不像这里给出的示例那么简单:https://www.postgresqltutorial.com/postgresql-recursive-query/
对于非递归的情况,我编写了一个函数,允许我让所有用户都被某个用户批准,看起来像这样(它还做了一些其他的事情,比如格式化结果基于另一个 table 中保存的信息,但它的核心部分是子查询中 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...
有什么想法吗?
这可能无法解决您的所有问题,但您会收到该错误仅仅是因为您在查询的递归部分的 FROM
子句中没有递归 table .它应该看起来像这样 -
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;
我有一个包含 table 的数据库,用于维护有关用户和其他用户的信息,这些用户可以为这些用户批准任务。这个审批人可以是用户的主管(维护在users
table的一对多关系中),或者是另一个明确赋予审批权的用户(维护在单独的多对多关系[=32]中) =]).
我的目标是找到给定用户的完整“批准”树(或链)(即允许该用户批准的人,以及这些批准者的批准链中的任何人)。由于上面描述的“显式其他批准者”的多对多关系,这不像查找 WHERE u1.username = u2.supervisor
那么简单,这不像这里给出的示例那么简单:https://www.postgresqltutorial.com/postgresql-recursive-query/
对于非递归的情况,我编写了一个函数,允许我让所有用户都被某个用户批准,看起来像这样(它还做了一些其他的事情,比如格式化结果基于另一个 table 中保存的信息,但它的核心部分是子查询中 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...
有什么想法吗?
这可能无法解决您的所有问题,但您会收到该错误仅仅是因为您在查询的递归部分的 FROM
子句中没有递归 table .它应该看起来像这样 -
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;