【问题标题】:How to avoid duplicates with hierarchical query如何使用分层查询避免重复
【发布时间】: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 的整个路径

标签: sql oracle hierarchy


【解决方案1】:

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                                                                                                    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-28
    • 1970-01-01
    • 2021-03-25
    • 2020-05-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    相关资源
    最近更新 更多