Oracle SQL 分层查询按顺序字段连接
Oracle SQL hierarical query connected by sequential field
我有一个这样的分层任务方案:
|-- task_1
|---- task_1_1
|------ task_1_1_1
|------ task_1_1_2
|---- task_1_2
|------ task_1_2_1
|------ task_1_2_2
|-- task_2
etc.
每个级别的任务数量可能会有所不同,因为此层次结构的深度可能会有所不同。
在数据库中,它们存储为一个序列:
name
sequence
parent_sequence
project_id
task_1
1
-1
1
task_1_1
2
1
1
task_1_1_1
3
2
1
task_1_1_2
4
2
1
task_1_2
5
1
1
task_1_2_1
6
5
1
task_1_2_2
7
5
1
task_2
8
-1
1
task_b_1
1
-1
2
task_b_1_1
2
1
2
task_b_1_1_1
3
2
2
为了重现层次结构,我使用了这个查询
SELECT
kid.name AS kid_name,
parent.name AS parent_name
FROM
task kid
LEFT JOIN task parent ON parent.sequence = kid.parent_sequence
AND parent.project_id = kid.parent_id
当我尝试使用分层查询时
SELECT
task.name AS task_name,
SYS_CONNECT_BY_PATH(task.name, '/') AS task_path
FROM
task
START WITH task.parent_sequence = -1
CONNECT BY PRIOR task.sequence = task.parent_sequence
它没有考虑条件 parent_id = parent_id
。
我尝试硬编码 WHERE parent_id = 1
和 LEFT JOIN
以便能够在 CONNECT BY PRIOR
和其他组合中执行 AND kid.project_id = parent.project_id
,但每次都会构建记录积分的层次结构。
匹配 task.sequence = task.parent_sequence
,因此出现错误的重复项,例如 task_1/task_b_1_1
。
问题是多个记录可以包含相同的 parent_sequence
和 sequence
(因为它们是在一个 project_id
的范围内计算的)。
我无法触摸数据库原理图。
如何构建按 project_id
分组的分层查询?
干杯
您可以将 project_id
比较添加到 CONNECT BY
过滤器:
SELECT project_id,
task.name AS task_name,
SYS_CONNECT_BY_PATH(task.name, '/') AS task_path
FROM task
START WITH task.parent_sequence = -1
CONNECT BY
PRIOR task.sequence = task.parent_sequence
AND PRIOR project_id = project_id
ORDER SIBLINGS BY project_id, sequence
其中,对于示例数据:
CREATE TABLE task (name, sequence, parent_sequence, project_id) AS
SELECT 'task_1', 1, -1, 1 FROM DUAL UNION ALL
SELECT 'task_1_1', 2, 1, 1 FROM DUAL UNION ALL
SELECT 'task_1_1_1', 3, 2, 1 FROM DUAL UNION ALL
SELECT 'task_1_1_2', 4, 2, 1 FROM DUAL UNION ALL
SELECT 'task_1_2', 5, 1, 1 FROM DUAL UNION ALL
SELECT 'task_1_2_1', 6, 5, 1 FROM DUAL UNION ALL
SELECT 'task_1_2_2', 7, 5, 1 FROM DUAL UNION ALL
SELECT 'task_2', 8, -1, 1 FROM DUAL UNION ALL
SELECT 'task_b_1', 1, -1, 2 FROM DUAL UNION ALL
SELECT 'task_b_1_1', 2, 1, 2 FROM DUAL UNION ALL
SELECT 'task_b_1_1_1', 3, 2, 2 FROM DUAL;
输出:
PROJECT_ID
TASK_NAME
TASK_PATH
1
task_1
/task_1
1
task_1_1
/task_1/task_1_1
1
task_1_1_1
/task_1/task_1_1/task_1_1_1
1
task_1_1_2
/task_1/task_1_1/task_1_1_2
1
task_1_2
/task_1/task_1_2
1
task_1_2_1
/task_1/task_1_2/task_1_2_1
1
task_1_2_2
/task_1/task_1_2/task_1_2_2
1
task_2
/task_2
2
task_b_1
/task_b_1
2
task_b_1_1
/task_b_1/task_b_1_1
2
task_b_1_1_1
/task_b_1/task_b_1_1/task_b_1_1_1
db<>fiddle here
我有一个这样的分层任务方案:
|-- task_1
|---- task_1_1
|------ task_1_1_1
|------ task_1_1_2
|---- task_1_2
|------ task_1_2_1
|------ task_1_2_2
|-- task_2
etc.
每个级别的任务数量可能会有所不同,因为此层次结构的深度可能会有所不同。
在数据库中,它们存储为一个序列:
name | sequence | parent_sequence | project_id |
---|---|---|---|
task_1 | 1 | -1 | 1 |
task_1_1 | 2 | 1 | 1 |
task_1_1_1 | 3 | 2 | 1 |
task_1_1_2 | 4 | 2 | 1 |
task_1_2 | 5 | 1 | 1 |
task_1_2_1 | 6 | 5 | 1 |
task_1_2_2 | 7 | 5 | 1 |
task_2 | 8 | -1 | 1 |
task_b_1 | 1 | -1 | 2 |
task_b_1_1 | 2 | 1 | 2 |
task_b_1_1_1 | 3 | 2 | 2 |
为了重现层次结构,我使用了这个查询
SELECT
kid.name AS kid_name,
parent.name AS parent_name
FROM
task kid
LEFT JOIN task parent ON parent.sequence = kid.parent_sequence
AND parent.project_id = kid.parent_id
当我尝试使用分层查询时
SELECT
task.name AS task_name,
SYS_CONNECT_BY_PATH(task.name, '/') AS task_path
FROM
task
START WITH task.parent_sequence = -1
CONNECT BY PRIOR task.sequence = task.parent_sequence
它没有考虑条件 parent_id = parent_id
。
我尝试硬编码 WHERE parent_id = 1
和 LEFT JOIN
以便能够在 CONNECT BY PRIOR
和其他组合中执行 AND kid.project_id = parent.project_id
,但每次都会构建记录积分的层次结构。
匹配 task.sequence = task.parent_sequence
,因此出现错误的重复项,例如 task_1/task_b_1_1
。
问题是多个记录可以包含相同的 parent_sequence
和 sequence
(因为它们是在一个 project_id
的范围内计算的)。
我无法触摸数据库原理图。
如何构建按 project_id
分组的分层查询?
干杯
您可以将 project_id
比较添加到 CONNECT BY
过滤器:
SELECT project_id,
task.name AS task_name,
SYS_CONNECT_BY_PATH(task.name, '/') AS task_path
FROM task
START WITH task.parent_sequence = -1
CONNECT BY
PRIOR task.sequence = task.parent_sequence
AND PRIOR project_id = project_id
ORDER SIBLINGS BY project_id, sequence
其中,对于示例数据:
CREATE TABLE task (name, sequence, parent_sequence, project_id) AS
SELECT 'task_1', 1, -1, 1 FROM DUAL UNION ALL
SELECT 'task_1_1', 2, 1, 1 FROM DUAL UNION ALL
SELECT 'task_1_1_1', 3, 2, 1 FROM DUAL UNION ALL
SELECT 'task_1_1_2', 4, 2, 1 FROM DUAL UNION ALL
SELECT 'task_1_2', 5, 1, 1 FROM DUAL UNION ALL
SELECT 'task_1_2_1', 6, 5, 1 FROM DUAL UNION ALL
SELECT 'task_1_2_2', 7, 5, 1 FROM DUAL UNION ALL
SELECT 'task_2', 8, -1, 1 FROM DUAL UNION ALL
SELECT 'task_b_1', 1, -1, 2 FROM DUAL UNION ALL
SELECT 'task_b_1_1', 2, 1, 2 FROM DUAL UNION ALL
SELECT 'task_b_1_1_1', 3, 2, 2 FROM DUAL;
输出:
PROJECT_ID TASK_NAME TASK_PATH 1 task_1 /task_1 1 task_1_1 /task_1/task_1_1 1 task_1_1_1 /task_1/task_1_1/task_1_1_1 1 task_1_1_2 /task_1/task_1_1/task_1_1_2 1 task_1_2 /task_1/task_1_2 1 task_1_2_1 /task_1/task_1_2/task_1_2_1 1 task_1_2_2 /task_1/task_1_2/task_1_2_2 1 task_2 /task_2 2 task_b_1 /task_b_1 2 task_b_1_1 /task_b_1/task_b_1_1 2 task_b_1_1_1 /task_b_1/task_b_1_1/task_b_1_1_1
db<>fiddle here