Соединение по предшествующему дереву должно быть симметричным - PullRequest
8 голосов
/ 15 сентября 2011

У меня есть соединение по предварительному запросу, которое создает мою древовидную структуру в Oracle. Это работает нормально, но у меня есть компонент, для корректного отображения которого требуется симметричное дерево.

Так что моя идея состоит в том, чтобы добавить больше узлов в дерево, если узел находится на уровне ниже, чем самый высокий уровень.

например. если у нас есть дерево

Root
  +- Node 1
    +- Leaf 1 (Level 3)
  +- Node 2
    +- Node 3
      +- Leaf 2 (Level 4)

Мне нужно изменить дерево во время выполнения, чтобы оно выглядело так:

Root
  +- Node 1
    +- Copy of Node 1
      +- Leaf 1 (Level 4)
  +- Node 2
    +- Node 3
      +- Leaf 2 (Level 4)

Это сделает мое дерево симметричным во время выполнения для работы компонента.

Существует ли простой запрос или функция Oracle, которые могут помочь в этом, или какой-либо оператор SQL, который может помочь в этом?

Ответы [ 2 ]

1 голос
/ 16 сентября 2011

Хорошо, после большого количества ошибок и ошибок я думаю, что нашел решение.

Так что, если у вас есть тестовая таблица, назовите ее xx_tree_test с 3 полями: cd, sup_cd и name; и я добавляю тестовые данные к нему, этот запрос

      SELECT CD,
           SUP_CD,
           LEVEL AS LVL,
           CASE WHEN CONNECT_BY_ISLEAF = 1 THEN 'L' ELSE NULL END AS LEAF,
           LPAD (' ', 3 * LEVEL, ' .') || NAME AS NAME
      FROM xx_tree_test
      START WITH SUP_CD IS NULL
      CONNECT BY PRIOR CD = SUP_CD;

даст такой результат:

enter image description here

Чтобы добавить дополнительный узел, чтобы привести Лист 1 и Лист 2 к одному уровню, вам нужен этот запрос:

 SELECT CD,
           SUP_CD,
           LEVEL AS LVL,
           CASE WHEN CONNECT_BY_ISLEAF = 1 THEN 'L' ELSE NULL END AS LEAF,
           LPAD (' ', 3 * LEVEL, ' .') || NAME AS NAME         
      FROM (WITH FULL_TREE
                 AS (    SELECT CD,
                                SUP_CD,
                                LEVEL AS LVL,
                                CASE
                                   WHEN CONNECT_BY_ISLEAF = 1 THEN 'L'
                                   ELSE NULL
                                END
                                   AS LEAF,
                                LPAD (' ', 3 * LEVEL, '  .') || NAME AS TREE_NAME,
                                NAME
                           FROM XX_TREE_TEST
                     START WITH SUP_CD IS NULL
                     CONNECT BY PRIOR CD = SUP_CD)
            SELECT A.NAME,
                   A.CD,
                   A.SUP_CD,
                   A.LVL
              FROM FULL_TREE A
             WHERE NVL (LEAF, 'z') != 'L'
            UNION ALL
            SELECT CASE
                      WHEN TREE1.LVL + TREE2.ROW_NUM_GENERATED - 1 =
                              (SELECT MAX (LVL) FROM FULL_TREE)
                      THEN
                         TREE1.NAME
                      ELSE
                         'Copy of ' || TREE1.NAME
                   END
                      AS NAME,
                   CASE
                      WHEN TREE1.LVL + TREE2.ROW_NUM_GENERATED - 1 =
                              (SELECT MAX (LVL) FROM FULL_TREE)
                      THEN
                         CD
                      ELSE
                         CD || '`' || TO_CHAR (TREE2.ROW_NUM_GENERATED)
                   END
                      AS CD,
                   CASE
                      WHEN TREE2.ROW_NUM_GENERATED = 1 THEN SUP_CD
                      ELSE CD || '`' || TO_CHAR (TREE2.ROW_NUM_GENERATED - 1)
                   END
                      AS SUP_CD,
                   TREE1.LVL + TREE2.ROW_NUM_GENERATED AS LVL
              FROM    (SELECT FULL_TREE.NAME,
                              FULL_TREE.CD,
                              FULL_TREE.SUP_CD,
                              FULL_TREE.LVL
                         FROM FULL_TREE
                        WHERE LEAF = 'L') TREE1
                   JOIN
                      (    SELECT LEVEL AS ROW_NUM_GENERATED
                             FROM DUAL
                       CONNECT BY LEVEL <= (SELECT MAX (LVL) FROM FULL_TREE)) TREE2
                   ON (SELECT MAX (LVL) FROM FULL_TREE) + 1 >=
                         TREE2.ROW_NUM_GENERATED + TREE1.LVL
            ORDER BY CD, LVL)
START WITH SUP_CD IS NULL
CONNECT BY PRIOR CD = SUP_CD;

Нет, этот запрос даст этот результат:

enter image description here

Итак, теперь осталось только упаковать его в красивый вид, чтобы скрыть огромное количество SQL.

0 голосов
/ 16 сентября 2011

Я не думаю, что это можно сделать в SQL, или, по крайней мере, я не могу придумать, как это сделать. Мне кажется, что запрос должен знать, сколько уровней ожидать, прежде чем он будет выполнен.

Возможно, тогда вам понадобится временная таблица, чтобы вы могли выполнить второй проход в своей логике, чтобы получить ее так, как вы этого хотите.

Есть ли у вас клиентский компонент, который будет отображать эти данные? Если это так, то это может быть самое простое место для этого второго прохода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...