Гость
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды. / 14 сообщений из 14, страница 1 из 1
24.09.2021, 22:05
    #40099970
lav314
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
/* Работаю с Hana, но хотелось бы решения на стандартном SQL, поэтому обращаюсь к форуму Oracle. */

Дано:

Есть (сохранена в таблице tab_hyer) уже построенная иерархия с колонками

rank, tree_size, parent_id, node_id, delete_flag

где
rank - номер текущей ноды (данное дерево упорядочено по rank от 1 до некоего максимального значения)
tree_size - размер под-дерева, исходящего из этого узла, то есть число всех дочерних нод первого порядка, их ноды, ноды этих нод и так далее до листьев. То есть если взять строку с rank = 4 и в ней будет стоять tree_size = 234, строки с ранками между 4+1 .... 4+234 будут всеми дочерними нодами всех порядов строки с rank = 4.
delete_flag - выставленный сторонним алгоритмом флаг, который говорит, что некоторые ноды дерева на самом деле ошибочные и должны быть удалены (такие ноды помечены delete_flag = true, остальные помечены false)

Для простоты предположить, что в иерархии одно дерево с одним корнем (rank = 1).
В дереве соотношение одни ко многим, то есть из parent может выходить несколько node, но у каждой node строго один parent.


Задача:
написать update поля delete_flag таблицы tab_hyer, который для всех дочек всех строк с delete_flag = true проставит delete_flag = true, то есть: если сторонний алгоритм пометил ноду как ошибочную, нужно пометить и всё исходящее из нее под-дерево на удаление.

Можно, но не хотелось бы, вместо update текущей таблицы создать новую таблицу с результатом апдейта.


Ограничения:
Можно использовать джойны, оконные функции, нельзя использовать pl/sql, циклы и встроенные функции работы с иерархиями типа "верну все ранки всех нод, исходящих из данной ноды, только скажи мне ее ранк".

Опционно:
вместо решения сообщить мне куда пройти, что решение, даже если оно существует, будет нечитабельно и неподдерживаемо в силу своей интеллектуальной изощренности и посоветовать отказаться от ограничений.
...
Рейтинг: 0 / 0
25.09.2021, 08:16
    #40099998
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
lav314
на стандартном SQL
нельзя использовать … встроенные функции работы с иерархиями типа "верну все ранки всех нод, исходящих из данной ноды, только скажи мне ее ранк"

куда пройти
И зачем ты тогда пришёл в Oracle?
...
Рейтинг: 0 / 0
25.09.2021, 15:29
    #40100017
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
lav314
То есть если взять строку с rank = 4 и в ней будет стоять tree_size = 234, строки с ранками между 4+1 .... 4+234 будут всеми дочерними нодами всех порядов строки с rank = 4.


Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
update tab_hyer
   set delete_flag = 'true'
 where rank in (
                select  rank + offset
                  from  tab_hyer,
                        lateral(
                                select  level offset
                                  from  dual
                                  connect by level <= tree_size
                               )
                  where delete_flag = 'true'
               )
/



SY.
P.S. LATERAL можно заменить на CROSS APPLY.
...
Рейтинг: 0 / 0
25.09.2021, 15:49
    #40100018
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
SY
Код: plsql
1.
connect by level

lav314
нельзя использовать … встроенные функции работы с иерархиями типа "верну все ранки всех нод, исходящих из данной ноды, только скажи мне ее ранк"
...
Рейтинг: 0 / 0
25.09.2021, 16:54
    #40100020
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
Код: plsql
1.
2.
3.
4.
update tab_hyer h1
  set delete_flag = 'true'
  where delete_flag = 'false'
    and exists (select null from tab_hyer h2 where h1.rank between h2.rank + 1 and h2.rank + h2.tree_size and h2.delete_flag = 'true')

...
Рейтинг: 0 / 0
25.09.2021, 16:55
    #40100021
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
Elic
SY
Код: plsql
1.
connect by level

lav314
нельзя использовать … встроенные функции работы с иерархиями типа "верну все ранки всех нод, исходящих из данной ноды, только скажи мне ее ранк"



Ну мультипликатор строк это не типа "верну все ранки всех нод, исходящих из данной ноды, только скажи мне ее ранк" и есть куча других мультипликаторов. Например:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
update tab_hyer
   set delete_flag = 'true'
 where rank in (
                select  rank + offset
                  from  tab_hyer,
                        lateral(
                                select  offset
                                  from  xmltable(
                                                 '1 to xs:integer(.)'
                                                 passing tree_size
                                                 columns
                                                   offset number path '.'
                                                )
                               )
                  where delete_flag = 'true'
               )
/



А можно и без мультипликатора строк:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
update tab_hyer
   set delete_flag = 'true'
 where rank in (
                with driver as (
                                select  rank + 1 rank_from,
                                        rank + tree_size rank_to
                                  from  tab_hyer
                                  where delete_flag = 'true'
                               )
                select  t.rank
                  from  tab_hyer t,
                        driver d
                  where t.rank between d.rank_from and d.rank_to
               )
/



SY.
...
Рейтинг: 0 / 0
25.09.2021, 17:11
    #40100025
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
SY
А можно и без мультипликатора строк:
Всё равно перемудрил.
...
Рейтинг: 0 / 0
26.09.2021, 08:23
    #40100059
serpv
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
а parent_id разве не надо в иерархии учитывать? казалось бы задача отметить потомков только нужных узлов.
...
Рейтинг: 0 / 0
26.09.2021, 16:25
    #40100082
lav314
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
serpv
а parent_id разве не надо в иерархии учитывать? казалось бы задача отметить потомков только нужных узлов.


Иерархия уже построена - все строки специально занумерованы (те самые ранки). Отменить нужно не только ближайших потомков нужных узлов (в ближайшем потомке мы храним parent и ваша идея сработает), а вообще всех потомков этого узла, в моем случае может быть до десяти уровней глубины. А мы ведь храним только ближайшего parent в строке и не знаем, какой parent был на три (для примера) уровня выше.
...
Рейтинг: 0 / 0
26.09.2021, 16:31
    #40100083
lav314
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
Благодарю SY за решения через drivers и Elic за решение через exist (выглядит очень изящно!).

Буду разбираться с этими решениями. Надеюсь, они учитывают, что интервалы удаляемых нод могут быть включены один в другой и т.д., то есть сторонний алгоритм мог пометить ноду 345 и ноду 367 на удаление, но при этом 367-я - дочка N-того уровня 345-й, то есть она и все ее дочки будут и так удалены при удалении потомков 345-й. Я не против, если поддерево 367-й будет помечено на удаление два раза :-)
...
Рейтинг: 0 / 0
26.09.2021, 16:55
    #40100086
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
lav314
Я не против, если поддерево 367-й будет помечено на удаление два раза
Так и говори, что ничего не понимаешь в SQL.
Elic
Код: plsql
1.
where delete_flag = 'false'

...
Рейтинг: 0 / 0
27.09.2021, 09:45
    #40100140
lav314
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
Так как я ничего не понимаю в SQL, прошу Elic рассмотреть следующую задачу

1) Есть изначальная таблица tab_hyer, заполненная простейшей иерархией ( 1<-- 2 <-- 3 <-- 4 )

Код: plsql
1.
2.
3.
4.
5.
6.
7.
сreate table tab_hyer as
select 1 as rank, 3 as tree_size, null as parent_id, 1 as node_id, false as delete_flag from dual union all -- это корневая нода
select 2, 2, 1, 2, false  from dual union all
select 3, 1, 2, 3, false  from dual union all
select 4, 0, 3, 4, false  from dual -- это единственный лист дерева
; 
commit;


2) Есть сторонний процесс, который пометил на удаление корневую и два нижележащих узла


Код: plsql
1.
2.
3.
4.
5.
6.
7.
update tab_hyer 
set
   delete_flag = true
where 
   rank in (1,2,3)
;
commit;



Таким образом теперь нода rank = 4 входит в три вложенных в друг друга поддерева, которые должны быть удалены.

3) Есть написанный Elic скрипт удаления дочерних нод всех уровней для удаленных ранее сторонним процессом узлов:

Код: plsql
1.
2.
3.
4.
update tab_hyer h1
  set delete_flag = 'true'
  where delete_flag = 'false'
    and exists (select null from tab_hyer h2 where h1.rank between h2.rank + 1 and h2.rank + h2.tree_size and h2.delete_flag = 'true')



4) Доказать (желательно средствами, доступными ничего не понимающему в sql человеку), что при исполнении скрипта из пункта 3 строка с rank = 4 будет проверена на условие
Код: plsql
1.
exists (select null from tab_hyer h2 where h1.rank between h2.rank + 1 and h2.rank + h2.tree_size and h2.delete_flag = 'true')


одни раз, а не три раза как предполагаю я.
...
Рейтинг: 0 / 0
27.09.2021, 10:58
    #40100151
serpv
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
lav314
В дереве соотношение одни ко многим, то есть из parent может выходить несколько node, но у каждой node строго один parent.
можете показать пример сreate table tab_hyer для этого случая, как заполняются rank, tree_size, parent_id, node_id в случае более чем одного листа в дереве?
...
Рейтинг: 0 / 0
27.09.2021, 13:16
    #40100184
Michael Isaev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды.
Elic
lav314
на стандартном SQL
нельзя использовать … встроенные функции работы с иерархиями типа "верну все ранки всех нод, исходящих из данной ноды, только скажи мне ее ранк"

куда пройти
И зачем ты тогда пришёл в Oracle?

Вот тоже хотел спросить, так как в HANA есть отличные от Oracle средства работы с иерархиями.
Кстати, пример топикстартер, таблица и столбцы очень похожи на те, что даются в документации HANA .
Что то мне кажется, что топикстартер - ленивый троль.
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Работа с иерархиями: удалить из иерархии всех дочек удаленной на предыдущем шаге ноды. / 14 сообщений из 14, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]