Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Вопрос по connect by  [new]
SQL_boy
Guest
Ребята всем привет!

Можете пояснить алгоритм работы иерархических запросов? В частности следующий пример:
With Test(Name) as  
    (select 'Tom' from dual)
    
select Name, level from Test   
    connect by level<=2


Возвращает то, что я и ожидал: одна запись выводится два раза по иерархии (1*2) = 2
NameLevel
Tom1
Tom2


Далее добавляю еще одну запись (кортеж) в таблицу и выполняю тот же запрос.
По моим ожиданиям: первым делом выполняется выборка из таблицы, далее к ней применяется условие в Connect by. Причем, так как не указан root, то родительской считается каждая запись. Т.е. для каждой записи будет возвращено две записи в соответствии с условием Connect by. Т.е я ожидаю что вернется: 1*2 + 1*2 = 4 записи. Но вернулось:
With Test(Name) as  
    (select 'Tom' from dual
    union
    select 'Jerry' from dual)
    
select Name, level from Test   
    connect by level<=2    

NameLevel
Jerry1
Jerry2
Tom2
Tom1
Jerry2
Tom2


Вернулось 6 записей! Можете пояснить почему? И как шел алгоритм?
20 сен 17, 17:15    [20809686]     Ответить | Цитировать Сообщить модератору
 Re: Вопрос по connect by  [new]
Elic
Member

Откуда:
Сообщений: 29976
SQL_boy
ернулось 6 записей! Можете пояснить почему? И как шел алгоритм?
Все являются детьми всех.
20 сен 17, 17:28    [20809731]     Ответить | Цитировать Сообщить модератору
 Re: Вопрос по connect by  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18336
SQL_boy
Вернулось 6 записей! Можете пояснить почему? И как шел алгоритм?

Для начала следует осознать, что Вы не указали условия соединения.
По аналогии с декартовым произведением, connect by в этих условиях пытается соединять всех со всеми.
Итого: 2 записи level 1 и по два чилда level 2 у каждой. 2*(1+2)=6
20 сен 17, 17:28    [20809732]     Ответить | Цитировать Сообщить модератору
 Re: Вопрос по connect by  [new]
SQL_boy
Guest
andrey_anonymous
SQL_boy
Вернулось 6 записей! Можете пояснить почему? И как шел алгоритм?

Для начала следует осознать, что Вы не указали условия соединения.
По аналогии с декартовым произведением, connect by в этих условиях пытается соединять всех со всеми.
Итого: 2 записи level 1 и по два чилда level 2 у каждой. 2*(1+2)=6


Ребята спасибо за ответы! Вроде сначала посчитал, что понял. А начал проверять и понял, что не понял =)
Сейчас озвучу свой ход мысли и параллельно вопросы, возникшие в процессе.

Есть таблица(отношение), содержащая две записи(кортежа). Применяем к ней выборку с connect by:
With Test(Name) as  
    (select 'Tom' from dual
    union
    select 'Jerry' from dual)
    
select Name, level from Test   
    connect by level<=2  


Итак, в соответствии с оракловой докой:
Oracle
1) Oracle selects the root row(s) of the hierarchy--those rows that satisfy the START WITH condition.
2) Oracle selects the child rows of each root row. Each child row must satisfy the condition of the CONNECT BY condition with respect to one of the root rows.


Так как в запросе явно не указано, какая запись является родительской (root), то считаем все записи root-ами.
'Tom'   --- Root
'Jerry' --- Root


Берем первую запись - 'Tom', она у нас root и, как понимаю условия соединения CONNECT BY к ней не применяется (поправьте если не так), а применяется это условие ко всем последующим записям. В нашем случае берем следующую запись Jerry и уже к ней применяем условие connect by level<=2. Вот здесь я думал, что выполняется реляционная операция - произведение(декартово): Jerry * 2 (т.к.connect by level<=2). В итоге получаем отношение из двух кортежей. Т.е у нас получается одна запись root - Tom (level=1), плюс два его потомка (две записи Jerry level 2), Итого три записи:

Name Level
'Tom'1
'Jerry'2
'Jerry'2


Далее переходит к второй root записи - Jerry и алгоритм повторяется. Получаем также три записи:
Name Level
'Jerry'1
'Tom'2
'Tom'2


На выходе получаем результат, который я приводил в первом посте этой темы:
Name Level
Jerry 1
Jerry 2
Tom 2
Tom 1
Jerry 2
Tom 2


Потом я решил переписать условие connect by, вместо 2 поставил 3:
With Test(Name) as  
    (select 'Tom' from dual
    union
    select 'Jerry' from dual)
    
select Name, level from Test   
    connect by level<=3    


Я ожидал, что вернется 8 записей: (Tom (root) + 3 потомка (Jerry)) + (Jerry(root) + 3 потомка Tom). Но результат был такой:
Name Level
Jerry 1
Jerry 2
Jerry 3
Tom 3
Tom 2
Jerry 3
Tom 3
Tom 1
Jerry 2
Jerry 3
Tom 3
Tom 2
Jerry 3
Tom 3


14 записей! Что-то не так я понял, алгоритм мой был ошибочный! Что не так?
22 сен 17, 14:05    [20815841]     Ответить | Цитировать Сообщить модератору
 Re: Вопрос по connect by  [new]
dbms_photoshop
Member

Откуда: sqlmdx.net
Сообщений: 5151
SQL_boy,

Еще раз, у тебя нет отношения родитель - потомок в условии соединения (оператор PRIOR),
соответсвенно когда выполняется переход на новый уровень все записи в таблице соответствуют условию соединения.
Переход на новый уровень выполняется пока не будет построено два уровня.
При переходе на новый уровень все записи таблицы являются детьми всех узлов уровня.

Когда это осознаешь - можешь переходить к анализу запроса.
With Test(Name) as  
    (select 'Tom' from dual
    union
    select 'Jerry' from dual)
    
select Name, level from Test   
    connect by rownum<=3    
22 сен 17, 14:13    [20815886]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить