Требуется иерархический запрос Oracle, который возвращает только полные деревья для записей, где дочерние элементы соответствуют поисковой строке - PullRequest
3 голосов
/ 13 октября 2011

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

Level  parent     id     text
---------------------------------------------
0      0          1      toplevel
1      1          2      foo
1      1          3      sumthin else
1      1          4      foo
0      0          7      toplevel2
1      7          8      secondlevel
1      7          9      anothersecondlevel

Мне нужно вернуть следующее, если пользователь выполняет поиск по 'foo':

0      0          1      toplevel
1      1          2      foo
1      1          4      foo

Реальный случай немного сложнее (т. Е. Три уровня в дереве, которые я хочу вернуть), но это отражает проблему.На английском языке верните дерево предков для узла, который соответствует строке поиска, начиная с соответствующего узла в текстовом столбце, и верните всех предков.

Я новичок в Oracle (по крайней мере, недавно) и попытался добавить вПредложение CONNECT BY без какого-либо успеха - всегда возвращает следующее:

1      1          2      foo
1      1          4      foo

PS - документы и примеры оракула подразумевают, что CONNECT_BY_ROOT будет захватывать предков, но все, что, кажется, делает, это возвращает верхний уровень (ROOT)значения.

Ответы [ 3 ]

3 голосов
/ 13 октября 2011

Для перемещения снизу вверх важный бит - это порядок значений после CONNECT BY PRIOR). order by используется для реверса вывода (поскольку корень - foo), а distinct удаляет дублирующиеся значения верхнего уровня.:

SELECT DISTINCT LEVEL, id, text
FROM t1
CONNECT BY PRIOR parent = id
START WITH text = 'foo'
ORDER BY LEVEL DESC

Примечание: если вы добавите дочерний элемент в foo и переключите идентификатор CONNCT BY PRIOR id = parent, вы получите дочерние элементы

, если вы хотите увидеть всю иерархию, которую можете найтиверхняя часть дерева (путем поиска строки без родителя)

SELECT id
FROM t1
WHERE parent=0
CONNECT BY PRIOR parent = id
START WITH text = 'foo'

, затем используйте это как идентификатор START WITH (и измените порядок обхода дерева во внешнем запросе, id = parent):

SELECT DISTINCT LEVEL, id, text
FROM t1
CONNECT BY PRIOR id = parent
START WITH id IN 
(
    SELECT id
    FROM t1
    WHERE parent=0
    CONNECT BY PRIOR parent = id
    START WITH text = 'foo'
)
ORDER BY LEVEL DESC
0 голосов
/ 26 января 2016

Моя часть «Иерархический запрос Oracle, который возвращает только полные деревья» будет выглядеть так:

SELECT Parent_ID    
     , Child_ID 
     , INITIAL_Parent_ID
     , child_level
     , INITIAL_Parent_ID || children_CHAIN AS CONNECTION_CHAIN
FROM ( SELECT CONNECT_BY_ROOT Parent_ID AS INITIAL_Parent_ID
            , Parent_ID
            , Child_ID
            , LEVEL AS child_level
            , SYS_CONNECT_BY_PATH(Child_ID, '/') AS children_chain
       FROM REF_DECOMMISSIONS
       CONNECT BY NOCYCLE Parent_ID = PRIOR Child_ID
     )
WHERE INITIAL_Parent_ID NOT IN (SELECT Child_ID FROM REF_DECOMMISSIONS)
;

Чтобы отфильтровать деревья с деревьями, содержащими определенных потомков, вам нужно добавить еще одно условие в последний WHERE для дальнейшей фильтрации INITIAL_Parent_ID. Запрос станет:

WITH ROOT_TREES AS
( SELECT Parent_ID  
       , Child_ID   
       , INITIAL_Parent_ID
       , child_level
       , INITIAL_Parent_ID || children_CHAIN AS CONNECTION_CHAIN
  FROM ( SELECT CONNECT_BY_ROOT Parent_ID AS INITIAL_Parent_ID
              , Parent_ID
              , Child_ID
              , LEVEL AS child_level
              , SYS_CONNECT_BY_PATH(Child_ID, '/') AS children_chain
         FROM REF_DECOMMISSIONS
         CONNECT BY NOCYCLE Parent_ID = PRIOR Child_ID
       )
  WHERE INITIAL_Parent_ID NOT IN (SELECT Child_ID FROM REF_DECOMMISSIONS)
)
SELECT * 
  FROM root_trees 
WHERE INITIAL_Parent_ID IN (SELECT INITIAL_Parent_ID 
                              FROM root_trees 
                             WHERE Child_ID = 123)
;
0 голосов
/ 13 октября 2011

В зависимости от вашего использования столбца LEVEL (согласно моему комментарию).

Информация об иерархических запросах Oracle: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/queries003.htm

Возвращает то, что вы запрашиваете, если LEVEL - Oracleпсевдостолбец:

WITH t AS (SELECT 0 AS parent,
                  1 AS id,
                  'toplevel' AS text FROM DUAL
           UNION
           SELECT 1 AS parent,
                  2 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 1 AS parent,
                  3 AS id,
                  'sumthin else' AS text FROM DUAL
           UNION
           SELECT 1 AS parent,
                  4 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 0 AS parent,
                  7 AS id,
                  'toplevel2' AS text FROM DUAL
           UNION
           SELECT 7 AS parent,
                  8 AS id,
                  'secondlevel' AS text FROM DUAL
           UNION
           SELECT 7 AS parent,
                  9 AS id,
                  'anothersecondlevel' AS text FROM DUAL
          ) 
SELECT UNIQUE
       level,
       parent,
       id,
       text
  FROM t
 START WITH text = 'foo'
 CONNECT BY PRIOR parent = id
 ORDER BY parent;

Возвращает:

LEVEL PARENT ID TEXT
    2      0  1 toplevel
    1      1  2 foo     
    1      1  4 foo     

Если LEVEL - это столбец в вашей таблице, то:

WITH t AS (SELECT 0 AS tlevel,
                  0 AS parent,
                  1 AS id,
                  'toplevel' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  1 AS parent,
                  2 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  1 AS parent,
                  3 AS id,
                  'sumthin else' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  1 AS parent,
                  4 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 0 AS tlevel,
                  0 AS parent,
                  7 AS id,
                  'toplevel2' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  7 AS parent,
                  8 AS id,
                  'secondlevel' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  7 AS parent,
                  9 AS id,
                  'anothersecondlevel' AS text FROM DUAL
          ) 
SELECT UNIQUE
       tlevel,
       parent,
       id,
       text
  FROM t
 START WITH text = 'foo'
 CONNECT BY PRIOR parent = id
 ORDER BY parent;

Возвращает:

TLEVEL PARENT ID TEXT
     0      0  1 toplevel
     1      1  2 foo     
     1      1  4 foo     

Надеюсь, это поможет ...

...