Простой рекурсивный запрос в Oracle - PullRequest
0 голосов
/ 01 мая 2018

У меня сейчас проблемы с пониманием и написанием рекурсивных запросов. Я понимаю, что рекурсивные запросы используются для поиска в иерархиях информации, но я не нашел в сети простого решения, которое могло бы перемещаться вверх по иерархии. Например, предположим, что у меня есть отношение, которое моделирует генеалогическое дерево:

create table family_tree (
child varchar(10)
parent varchar(10)
);

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

Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 02 мая 2018

Существует синтаксис ANSI, с которым я не очень хорошо знаком, и есть синтаксис Oracle, который я обычно использую. Синтаксис Oracle использует предложение CONNECT BY ... PRIOR для построения дерева и предложение START WITH, которое сообщает базе данных, с чего начать обход дерева. Это будет выглядеть так:

SELECT child, parent, level
  FROM family_tree
CONNECT BY ...
START WITH ...

Предложение START WITH проще. Вы смотрите "вверх" на дерево, поэтому вы выбираете ребенка, с которого хотите начать ходить по дереву. Так что это будет выглядеть как START WITH parent = 'John'. Это наша строка 1-го уровня. Я предполагаю, что в ряду Джона он будет его родителем, а детей нет, так как это низ дерева.

Теперь подумайте о том, как строки в дереве связаны друг с другом. Если мы смотрим на строку уровня 2, как мы узнаем, является ли она правильной строкой строки «Джон»? В этом случае у него будет Джон в дочернем столбце. Итак, мы хотим пункт: CONNECT BY PRIOR parent = child. Это означает, что «родитель предыдущего ряда равен потомку этого ряда»

Итак, запрос выглядит так:

SELECT child, parent, level
  FROM family_tree
CONNECT BY PRIOR parent = child
START WITH parent = 'John'

Пример SQL Fiddle

(Это немного странный пример, поскольку у настоящих детей есть два родителя, но это усложнит ситуацию.)

0 голосов
/ 01 мая 2018

Вы знакомы с таблицей SCOTT.EMP? Он находится в «стандартной» SCOTT схеме (которая, к сожалению, больше не входит в комплект поставки каждой копии базы данных Oracle, начиная с версии 12.1 или около того). Проверьте свою базу данных: вы можете найти ее там. Или спросите об этом вашего администратора.

В любом случае: в таблице показаны 14 сотрудников малого бизнеса, и она включает в себя идентификатор сотрудника, а также идентификатор сотрудника его или ее менеджера. Итак, предположим, что вы начинаете с определенного сотрудника и хотите найти его или ее босса высшего уровня. (Аналогично вашей тестовой задаче.) В этой конкретной иерархии «предок» высшего уровня уникален, но это не имеет значения; рекурсивный запрос работал бы одинаково, если бы в каждом отделе был «начальник отдела» и не было руководителя над руководителями отдела.

При таком расположении легко определить «босса всех боссов» - у него нет босса. В его строке идентификатор менеджера равен null. Это очень распространенное расположение для «корня» (или «корней») древовидных иерархий.

Вот как вы можете найти начальника, начиная с определенного идентификатора сотрудника и используя рекурсивный запрос - я понимаю, что именно вы хотите практиковаться. (То есть: если я правильно понимаю, вы не заинтересованы в решении проблемы «любыми средствами»; скорее, вы хотите увидеть, как работают рекурсивные запросы, в небольшом примере, чтобы вы могли понять ВСЕ, что происходит.)

with
  r ( empno, mgr ) as (
    select  empno, mgr      -- ANCHOR leg of recursive query
      from  scott.emp
      where empno = 7499
    union all
    select  e.empno, e.mgr  -- RECURSIVE leg of recursive query
      from  scott.emp e inner join r on e.empno = r.mgr
  )
select empno
from   r
where  mgr is null
;

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

0 голосов
/ 02 мая 2018

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

Используйте иерархический запрос и функцию SYS_CONNECT_BY_PATH( column_name, delimiter ):

Установка Oracle 18 :

create table family_tree (
  child varchar(10),
  parent varchar(10)
);

INSERT INTO family_tree ( child, parent )
  SELECT 'B', 'A' FROM DUAL UNION ALL
  SELECT 'C', 'B' FROM DUAL UNION ALL
  SELECT 'D', 'C' FROM DUAL UNION ALL
  SELECT 'E', 'D' FROM DUAL UNION ALL
  SELECT 'F', 'C' FROM DUAL;

Запрос 1 :

SELECT SYS_CONNECT_BY_PATH( parent, ' -> ' ) || ' -> ' || child AS path
FROM   family_tree
START WITH parent = 'A'
CONNECT BY PRIOR child = parent;

Результаты

PATH
-------------------------
 -> A -> B
 -> A -> B -> C
 -> A -> B -> C -> D
 -> A -> B -> C -> D -> E
 -> A -> B -> C -> F
0 голосов
/ 01 мая 2018

Вы можете использовать connect by предложение.

В вашем случае SQL может выглядеть так:

select child, parent, level
from family_tree 
connect by prior parent = child
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...