我在PostgreSQL 9.6.6上编写一个sql脚本时遇到问题,该脚本使用步骤的父子ID对流程中的步骤进行排序,并根据流程ID对这些步骤进行分组/分区。我在此处找不到这种特殊情况,因此如果遗漏了,我深表歉意,请您在评论中提供指向解决方案的链接。
案例:我有一张这样的桌子:
processID | stepID | parentID
1 1 NULL
1 3 5
1 2 4
1 4 3
1 5 1
2 1 NULL
2 3 5
2 2 4
2 4 3
2 5 1
现在,我必须从每个processID的parentID为空的步骤开始对这些步骤进行排序。
注意:我不能简单地订购StepID或parentID,因为我在整个流程中放入的新步骤比流程中的最后一个步骤(连续生成代理项密钥)获得更高的StepID。
我必须为每个processID订购步骤,以便接收以下输出:
processID | stepID | parentID
1 1 NULL
1 5 1
1 3 5
1 4 3
1 2 4
2 1 NULL
2 5 1
2 3 5
2 4 3
2 2 4
我试图用递归的CTE函数来实现这一点:
WITH RECURSIVE
starting (processID,stepID, parentID) AS
(
SELECT b.processID,b.stepID, b.parentID
FROM process b
WHERE b.parentID ISNULL
),
descendants (processID,stepID, parentID) AS
(
SELECT b.processID,b.stepID, b.stepparentID
FROM starting b
UNION ALL
SELECT b.processID,b.stepID, b.parentID
FROM process b
JOIN descendants AS c ON b.parentID = c.stepID
)
SELECT * FROM descendants
结果不是我想要的。由于我们有数百个进程,我收到一个列表,其中第一个记录是不同的processid,它们的parentID值为空。
我想我必须在processID上再次递归整个脚本,但不知道如何递归。
谢谢你的帮助!
最佳答案
您应该计算每个步骤的级别:
with recursive starting as (
select processid, stepid, parentid, 0 as level
from process
where parentid is null
union all
select p.processid, p.stepid, p.parentid, level+ 1
from starting s
join process p on s.stepid = p.parentid and s.processid = p.processid
)
select *
from starting
order by processid, level
processid | stepid | parentid | level
-----------+--------+----------+-------
1 | 1 | | 0
1 | 5 | 1 | 1
1 | 3 | 5 | 2
1 | 4 | 3 | 3
1 | 2 | 4 | 4
2 | 1 | | 0
2 | 5 | 1 | 1
2 | 3 | 5 | 2
2 | 4 | 3 | 3
2 | 2 | 4 | 4
(10 rows)
当然,如果不需要,可以跳过最终选择中的最后一列。