如何识别和列出 Postgres 中的循环引用元素
How to identify and list Circular Reference elements in Postgres
我有一个 employee , manager 层次结构,最终可能会循环。
例如:
28397468N>88518119N>87606705N>28397468N
Create Table emp_manager ( Emp_id varchar(30), Manager_id varchar(30));
Insert into emp_manager values ('28397468N','88518119N');
Insert into emp_manager values ('88518119N','87606705N');
Insert into emp_manager values ('87606705N','28397468N');
我的要求是:
当调用我的 proc 并且 emp_manager table 中存在循环层次结构时,我们应该 return 列出层次结构中的员工的错误。
下面的 link 包含一些有用的信息:
https://mccalljt.io/blog/2017/01/postgres-circular-references/
我修改如下:
select * from (
WITH RECURSIVE circular_managers(Emp_id, Manager_id, depth, path, cycle) AS (
SELECT u.Emp_id, u.Manager_id, 1,
ARRAY[u.Emp_id],
false
FROM emp_manager u
UNION ALL
SELECT u.Emp_id, u.Manager_id, cm.depth + 1,
(path || u.Emp_id)::character varying(32)[],
u.Emp_id = ANY(path)
FROM emp_manager u, circular_managers cm
WHERE u.Emp_id = cm.Manager_id AND NOT cycle
)
select
distinct (path) d
FROM circular_managers
WHERE cycle
AND path[1] = path[array_upper(path, 1)]) cm
但是,问题是,它 return 层次结构的所有组合:
{28397468N,88518119N,87606705N,28397468N}
{87606705N,28397468N,88518119N,87606705N}
{88518119N,87606705N,28397468N,88518119N}
I need a simple answer like this:
28397468N>88518119N>87606705N>28397468N
even this will do:
28397468N>88518119N>87606705N
请帮忙!
要防止循环引用,您可以使用闭包 table 和触发器 - 如 中所述
闭包 table 还可以让您轻松获得给定主管的所有下属(无论在层次结构中有多深) - 或者给定员工的所有直属上司(直到根)。
在使用 rebuild_tree
存储过程之前,您必须从层次结构中删除所有循环引用。
因此所有参考文献:
{28397468N,88518119N,87606705N,28397468N}
{87606705N,28397468N,88518119N,87606705N}
{88518119N,87606705N,28397468N,88518119N}
是正确的,但只是从不同的元素开始。
I need a simple answer like this: 28397468N>88518119N>87606705N>28397468N
所以需要的是针对相同圆圈参考的过滤器。
让我们以某种方式做到这一点:
- 对数组中的不同项目进行排序
- 将它们聚合回来 - 因此对于所有引用,它将是'{28397468N,87606705N,88518119N}'
- 使用 DISTINCT 的生成值 FIRST_VALUE
WITH D (circle_ref ) AS (
VALUES
('{28397468N,88518119N,87606705N,28397468N}'::text[]),
('{87606705N,28397468N,88518119N,87606705N}'::text[]),
('{88518119N,87606705N,28397468N,88518119N}'::text[])
), ordered AS (
SELECT
D.circle_ref,
(SELECT ARRAY_AGG(DISTINCT el ORDER BY el) FROM UNNEST(D.circle_ref) AS el ) AS ordered_circle
FROM
D
)
SELECT DISTINCT
FIRST_VALUE (circle_ref) OVER (PARTITION BY ordered_circle ORDER BY circle_ref) AS circle_ref
FROM
ordered;
circle_ref
{28397468N,88518119N,87606705N,28397468N}
DB Fiddle: https://www.db-fiddle.com/f/6ytb2v11s8T95PPLoTZZed/0
我有一个 employee , manager 层次结构,最终可能会循环。
例如: 28397468N>88518119N>87606705N>28397468N
Create Table emp_manager ( Emp_id varchar(30), Manager_id varchar(30));
Insert into emp_manager values ('28397468N','88518119N');
Insert into emp_manager values ('88518119N','87606705N');
Insert into emp_manager values ('87606705N','28397468N');
我的要求是: 当调用我的 proc 并且 emp_manager table 中存在循环层次结构时,我们应该 return 列出层次结构中的员工的错误。
下面的 link 包含一些有用的信息: https://mccalljt.io/blog/2017/01/postgres-circular-references/
我修改如下:
select * from (
WITH RECURSIVE circular_managers(Emp_id, Manager_id, depth, path, cycle) AS (
SELECT u.Emp_id, u.Manager_id, 1,
ARRAY[u.Emp_id],
false
FROM emp_manager u
UNION ALL
SELECT u.Emp_id, u.Manager_id, cm.depth + 1,
(path || u.Emp_id)::character varying(32)[],
u.Emp_id = ANY(path)
FROM emp_manager u, circular_managers cm
WHERE u.Emp_id = cm.Manager_id AND NOT cycle
)
select
distinct (path) d
FROM circular_managers
WHERE cycle
AND path[1] = path[array_upper(path, 1)]) cm
但是,问题是,它 return 层次结构的所有组合:
{28397468N,88518119N,87606705N,28397468N}
{87606705N,28397468N,88518119N,87606705N}
{88518119N,87606705N,28397468N,88518119N}
I need a simple answer like this:
28397468N>88518119N>87606705N>28397468N
even this will do:
28397468N>88518119N>87606705N
请帮忙!
要防止循环引用,您可以使用闭包 table 和触发器 - 如 中所述 闭包 table 还可以让您轻松获得给定主管的所有下属(无论在层次结构中有多深) - 或者给定员工的所有直属上司(直到根)。
在使用 rebuild_tree
存储过程之前,您必须从层次结构中删除所有循环引用。
因此所有参考文献:
{28397468N,88518119N,87606705N,28397468N}
{87606705N,28397468N,88518119N,87606705N}
{88518119N,87606705N,28397468N,88518119N}
是正确的,但只是从不同的元素开始。
I need a simple answer like this: 28397468N>88518119N>87606705N>28397468N
所以需要的是针对相同圆圈参考的过滤器。
让我们以某种方式做到这一点:
- 对数组中的不同项目进行排序
- 将它们聚合回来 - 因此对于所有引用,它将是'{28397468N,87606705N,88518119N}'
- 使用 DISTINCT 的生成值 FIRST_VALUE
WITH D (circle_ref ) AS (
VALUES
('{28397468N,88518119N,87606705N,28397468N}'::text[]),
('{87606705N,28397468N,88518119N,87606705N}'::text[]),
('{88518119N,87606705N,28397468N,88518119N}'::text[])
), ordered AS (
SELECT
D.circle_ref,
(SELECT ARRAY_AGG(DISTINCT el ORDER BY el) FROM UNNEST(D.circle_ref) AS el ) AS ordered_circle
FROM
D
)
SELECT DISTINCT
FIRST_VALUE (circle_ref) OVER (PARTITION BY ordered_circle ORDER BY circle_ref) AS circle_ref
FROM
ordered;
circle_ref |
---|
{28397468N,88518119N,87606705N,28397468N} |
DB Fiddle: https://www.db-fiddle.com/f/6ytb2v11s8T95PPLoTZZed/0