【发布时间】:2016-05-01 14:39:08
【问题描述】:
这和我上次的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)
但随后它变得丑陋和凌乱,当其他程序员尝试对其进行维护时,将难以对其进行维护。
那么,有没有更好/更易读的方式只采用完整路径记录?
提前致谢。
【问题讨论】:
-
分层查询中没有
START WITH子句。此子句确定作为表中层次结构根节点的记录。如果没有这个子句,thable 中的所有记录都被视为根节点,Oracle 将每个记录一个接一个地作为“根”,并为每个记录生成一个层次结构。例如,如果您有 1-2-3-4,那么如果没有START WITH col=1,您将获得总共 4 个层次结构:1-2-3-4、2-3-4、3-4 和 4。查看我的最后一个答案:stackoverflow.com/questions/36964508/… - 那里有START WITH子句。 -
这基本上就是我想要的,我想要表中每条记录的路径,而不仅仅是层次结构的根(看我的输出示例),但我只想要每个记录的整个路径其中之一..@kordirko。尽管我在上一个问题中接受了您的回答,但它没有提供正确的结果,我只是想要另一种方法来处理子字符串..
-
如果不查看表中的数据很难诊断。请创建一个最小可验证示例:stackoverflow.com/help/mcve表中的输入数据(仅几条记录即可),以及查询生成的实际结果,以及此示例数据的预期结果。
-
@kordirko 我已经用数据和我期望的确切输出更新了这个问题。查询返回预期的输出,但有额外的,例如 family_code = 4。它将作为以下组合返回:
(4,3,6,null..)、(4,3,null...)、(4,null,null.....)而不是只有(4,3,6,null...)这是4的整个路径