2016-05-01 2 views
0

Это относится немного к моему последним 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 bysubstr() и 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

В иерархическом запросе нет предложения «СТАРТ С». Этот раздел определяет записи, которые являются корневыми узлами иерархии в вашей таблице. Без этого предложения все записи в thable рассматриваются как корневые узлы, а Oracle берет каждую запись один за другим как «root», а для каждого генерирует иерархию. Например, если у вас 1-2-3-4, то без «START WITH col = 1» вы получите в общей сложности 4 иерархии: 1-2-3-4, 2-3-4, 3-4 и 4. Посмотрите мой последний ответ: http://stackoverflow.com/questions/36964508/how-to-get-the-path-of-an-hairsp; -иерархия - есть пункт «НАЧАТЬ С». – krokodilko

+0

В основном, что я хочу, мне нужен путь для каждой записи в таблице, а не только для корней иерархии (посмотрите на мой пример вывода), но я хочу только весь путь каждого из них. @kordirko , И хотя я принял ваш ответ в последнем вопросе, он не дал правильного результата, мне просто нужен другой подход подстроки. – sagi

+0

Трудно диагностировать, не глядя на данные в таблице. Создайте минимальный проверенный пример: http://stackoverflow.com/help/mcve входных данных в таблице (всего несколько записей будет достаточно), вместе с фактическим результатом, сгенерированным запросом, и результатом desiderd для этого примера данных , – krokodilko

ответ

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                          
Смежные вопросы