这与我上次的Question
有点关系无论如何,我有一个分层表结构如下(实际上,代码将始终是varchar2(3),数字只是为了简化):
Family_code | Parent_Family_Code | ....
1 2
2 4
3 6
4 3
6 null
8 null
9 8
......................
输出应为:
Family_code | parent_1 | p_2 | p_3 | p_4 | p_5 | .....
1 2 4 3 6 null null.....
2 4 3 6 null null...
3 6 null...
4 3 6 null ...
6 null...
8 null...
9 8 null..
我使用connect by
substr()
和connect_by_path
提出了一个解决方案,这会产生预期的输出,但是有重复项 - 不完全重复,但是让我们说family_code = 1生成结果(1,2,4,3,6,null..)
和(1,2,4,3,null,null...)
以及(1,2,4,null...)
而不是仅仅(1,2,4,3,6,null ...)这是完整路径。这是查询:
SELECT s.family_code,
s.parent_family_code_1,
s.parent_family_code_2,
CASE WHEN length(s.family_path) - (4 * 3 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 3 + 2), 3) ELSE NULL END as parent_family_code_3,
CASE WHEN length(s.family_path) - (4 * 4 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 4 + 2), 3) ELSE NULL END as parent_family_code_4,
CASE WHEN length(s.family_path) - (4 * 5 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 5 + 2), 3) ELSE NULL END as parent_family_code_5,
CASE WHEN length(s.family_path) - (4 * 6 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 6 + 2), 3) ELSE NULL END as parent_family_code_6,
CASE WHEN length(s.family_path) - (4 * 7 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 7 + 2), 3) ELSE NULL END as parent_family_code_7,
CASE WHEN length(s.family_path) - (4 * 8 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 8 + 2), 3) ELSE NULL END as parent_family_code_8,
CASE WHEN length(s.family_path) - (4 * 9 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 9 + 2), 3) ELSE NULL END as parent_family_code_9,
CASE WHEN length(s.family_path) - (4 * 10 + 2) > 0 THEN substr(s.family_path, length(s.family_path) - (4 * 10 + 2), 3) ELSE NULL END as parent_family_code_10
FROM (SELECT t.family_code,
t.parent_family_code as parent_family_code_1,
prior t.parent_family_code as parent_family_code_2,
sys_connect_by_path(t.family_code, ',') as family_path
FROM table t
connect by prior t.family_code = t.parent_family_code) s
我可以使用子查询通过比较路径的最大长度并仅使用它来修复它:
SELECT * FROM (
SELECT t.family_code,
t.parent_family_code as parent_family_code_1,
prior t.parent_family_code as parent_family_code_2,
sys_connect_by_path(t.family_code, ',') as family_path
FROM WIZ_PRODUCT_FAMILY_CODES t
connect by prior t.family_code = t.parent_family_code) t
WHERE length(t.family_path) = (SELECT MAX(length(sys_connect_by_path(s.family_code, ','))) FROM WIZ_PRODUCT_FAMILY_CODES s
where s.family_code = t.family_code
connect by prior s.family_code = s.parent_family_code)
然而,当其他程序员尝试使用它时,它会变得丑陋而且很难以维护它。
那么,只有完整路径记录有更好/更易读的方式吗?
提前致谢。
答案 0 :(得分:0)
选择my answer from your other question并注释掉WHERE CONNECT_BY_ISLEAF = 1
过滤器...
Oracle安装程序:
CREATE TABLE table_name ( Family_code, Parent_Family_Code ) AS
SELECT 1, 2 FROM DUAL UNION ALL
SELECT 2, 4 FROM DUAL UNION ALL
SELECT 3, 6 FROM DUAL UNION ALL
SELECT 6, NULL FROM DUAL UNION ALL
SELECT 4, 3 FROM DUAL UNION ALL
SELECT 4, 5 FROM DUAL UNION ALL
SELECT 5, NULL FROM DUAL UNION ALL
SELECT 8, NULL FROM DUAL UNION ALL
SELECT 9, 8 FROM DUAL;
<强>查询强>:
SELECT TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth, NULL, 1 ) ) AS family_code,
CASE WHEN max_depth > 1 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 1, NULL, 1 ) ) END AS p1,
CASE WHEN max_depth > 2 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 2, NULL, 1 ) ) END AS p2,
CASE WHEN max_depth > 3 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 3, NULL, 1 ) ) END AS p3,
CASE WHEN max_depth > 4 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 4, NULL, 1 ) ) END AS p4,
CASE WHEN max_depth > 5 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 5, NULL, 1 ) ) END AS p5,
CASE WHEN max_depth > 6 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 6, NULL, 1 ) ) END AS p6,
CASE WHEN max_depth > 7 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 7, NULL, 1 ) ) END AS p7,
CASE WHEN max_depth > 8 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 8, NULL, 1 ) ) END AS p8,
CASE WHEN max_depth > 9 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 9, NULL, 1 ) ) END AS p9,
CASE WHEN max_depth > 10 THEN TO_NUMBER( REGEXP_SUBSTR( path, '/(\d+)', 1, max_depth - 10, NULL, 1 ) ) END AS p10
FROM (
SELECT SYS_CONNECT_BY_PATH( Family_code, '/' ) AS path,
LEVEL AS max_depth
FROM table_name
--WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR Family_Code = Parent_Family_Code
START WITH Parent_Family_Code IS NULL
);
<强>输出强>:
FAMILY_CODE P1 P2 P3 P4 P5 P6 P7 P8 P9 P10
----------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
5
4 5
2 4 5
1 2 4 5
6
3 6
4 3 6
2 4 3 6
1 2 4 3 6
8
9 8