powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Поиск комбинаций строк в таблице
25 сообщений из 40, страница 1 из 2
Поиск комбинаций строк в таблице
    #39457928
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Хочу посоветоваться в решении прикладной задачи. Свой вариант написал, работает точно и быстро, но есть ощущение, что можно сделать "красивее".

Есть абстрактная система CRM, в ней список служб (продуктов) в иерархической форме.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
create table prods as (
  select 1 as prod_id,  null  as parent_id, 'ROOT1'    as prod_name from dual union
  select 2 as prod_id,  1     as parent_id, 'PROD11'   as prod_name from dual union
  select 3 as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 4 as prod_id,  3     as parent_id, 'PROD121'  as prod_name from dual union
  select 5 as prod_id,  3     as parent_id, 'PROD123'  as prod_name from dual union
  select 10 as prod_id, null  as parent_id, 'ROOT1'    as prod_name from dual union
  select 20 as prod_id, 10    as parent_id, 'PROD11'   as prod_name from dual union
  select 30 as prod_id, 10    as parent_id, 'PROD12'   as prod_name from dual union
  select 31 as prod_id, 10    as parent_id, 'PROD13'   as prod_name from dual union
  select 40 as prod_id, 30    as parent_id, 'PROD121'  as prod_name from dual union
  select 41 as prod_id, 30    as parent_id, 'PROD122'  as prod_name from dual union
  select 42 as prod_id, 30    as parent_id, 'PROD123'  as prod_name from dual 
);

-- product tree
select 
  p.prod_id                                 as prod_id, 
  connect_by_root p.prod_id                 as root_id, 
  connect_by_root p.prod_name               as root_prod, 
  rpad(' ', (level-1)*2, ' ')||p.prod_name  as prod_name, 
  sys_connect_by_path(p.prod_name, '|')     as prod_path
from prods p
start with parent_id is null 
connect by prior prod_id = parent_id;        



Есть список комбинаций продуктов.

У меня ключом для комбинаций используются полные пути, так обеспечивается точность иерархии. Мой вариант происходит из excel-таблицы, составленной архитекторами и BA, возможно это повлияло на способ решения задачи. В принципе, список комбинаций может быть в любой форме, главное чтобы сохранились коды (имена) продуктов, их расположение в иерархии отосительно друг друга, была возможность добавлять дополнительные ключи (напр.: параметр продукта из другой таблицы, его состояние, и т.п.).

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

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
create table prod_map as
(
  -- map1
  select 'MAP_1'  map_id, 1     map_group, 1    map_depth, '|ROOT1'                 prod_path, 'root'   pos from dual union
  select 'MAP_1'  map_id, 1     map_group, 1    map_depth, '|ROOT1|PROD11'          prod_path, 'prod1'  pos from dual union 
  select 'MAP_1'  map_id, 1     map_group, 1    map_depth, '|ROOT1|PROD12'          prod_path, 'prod2'  pos from dual union 
  -- map2
  select 'MAP_2'  map_id, 1     map_group, 2    map_depth, '|ROOT1'                 prod_path, 'root'   pos from dual union
  select 'MAP_2'  map_id, 1     map_group, 2    map_depth, '|ROOT1|PROD11'          prod_path, 'prod1'  pos from dual union 
  select 'MAP_2'  map_id, 1     map_group, 2    map_depth, '|ROOT1|PROD12'          prod_path, 'prod2'  pos from dual union 
  select 'MAP_2'  map_id, 1     map_group, 2    map_depth, '|ROOT1|PROD13'          prod_path, 'prod3'  pos from dual union 
  -- map3
  select 'MAP_3'  map_id, null  map_group, null map_depth, '|ROOT1'                 prod_path, 'root'   pos from dual union 
  select 'MAP_3'  map_id, null  map_group, null map_depth, '|ROOT1|PROD12'          prod_path, 'prod1'  pos from dual union
  select 'MAP_3'  map_id, null  map_group, null map_depth, '|ROOT1|PROD12|PROD121'  prod_path, 'prod2'  pos from dual union 
  select 'MAP_3'  map_id, null  map_group, null map_depth, '|ROOT1|PROD12|PROD122'  prod_path, 'prod3'  pos from dual  
);



Комбинации могут частично пересекаться - MAP_1 и MAP_2 похожи, в MAP_2 на один продукт больше. В таких случаях при выборе используются параметры map_group и map_depth, выбирается максимальная "глубина" для совпадающей группы.

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

Моё решение - совпадения проверять по строке пути и точному количеству строк.
Делаю вспомогательную табличку:
Код: plsql
1.
2.
3.
create table prod_map_qty as (
  select map_id, count(*) as qty from prod_map group by map_id
);



Главный select. Немного громоздкий, но достаточно быстрый. Найденные комбинации разворачиваются в одну строку пивотом (отдельные столбцы для каждого продукта), и полученный результат фильтруется по map_group и map_depth.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
with
prod_list as (
  select 
    p.prod_id                             as prod_id, 
    connect_by_root p.prod_id             as root_id, 
    connect_by_root p.prod_name           as root_prod, 
    p.prod_name                           as prod_name, 
    sys_connect_by_path(p.prod_name, '|') as prod_path,
    level as lvl
  from prods p
  start with parent_id is null 
  connect by prior prod_id = parent_id                        
)
select * from (
    -- RANK result by map_group, map_depth
    -- get one with maximum map_depth (highest rank)
    SELECT t.*, ROW_NUMBER() OVER (PARTITION BY root_id, map_group ORDER BY map_depth DESC) rank
    FROM 
      ( 
        -- pivot product list from tree form to single row form
        select 
          map_id, map_group, map_depth, 
          unmapped_prod_id, unmapped_prod_path,
          root_prod, root_id, 
          root_pid, prod1_pid, prod2_pid, prod3_pid, prod4_pid
        from 
          (
            -- product list with mapped and unmapped products, tree form, ready for pivoting 
            select 
              v.map_id, v.map_group, v.map_depth, 
              v.unmapped_prod_id, v.unmapped_prod_path,
              v.root_prod, v.root_id, v.prod_id, v.pos
            from 
              (
                -- join product list with mapping tree table
                select
                  vv.map_id,vv.map_group, vv.map_depth, 
                  -- unmapped id
                  case 
                    when vv.prod_id is null then p.prod_id
                    else null
                  end unmapped_prod_id,
                  -- unmapped path
                  case 
                    when vv.prod_id is null then p.prod_path
                    else null
                  end unmapped_prod_path,
                  p.root_prod, p.root_id, p.prod_id, p.prod_path,
                  vv.pos
                from prod_list p
                left join -- return all products, including not matched by mapping table
                  (
                    -- get matched combinations of products 
                    select 
                      vmap.* 
                    from 
                      (
                        -- find matched products combinations by mapping tree table
                        select 
                          m.*, pp.root_id, pp.prod_id,
                          sum(1) over (partition by m.map_id, pp.root_id) as qty  -- qty of matched product paths for ID
                        from prod_map m
                        join prod_list pp on 
                          pp.prod_path = m.prod_path  --  same product path
--                              and ......                  --  additional checks (states, parameters, etc.) 
                      ) vmap
                      -- get fully matched combinations (qty of matched products == qty of products by mapping table)
                      join prod_map_qty q on q.map_id = vmap.map_id and q.qty = vmap.qty
                  ) vv on vv.prod_id = p.prod_id
              ) v
          ) 
          -- PIVOT result to single row for each mapped_id
          PIVOT ( max(prod_id) AS pid FOR (pos) IN 
            (
             'root' as root,
             'prod1' as prod1, 
             'prod2' as prod2, 
             'prod3' as prod3, 
             'prod4' as prod4
            )
          ) -- end PIVOT 
      ) t
  ) res
  WHERE ( res.map_group is null ) 
        OR 
        -- for multiple map_group - get one with highest priority (highest rank)
        ( res.map_group is not null and res.rank = 1 )
order by root_id, map_id;



Если на вход подать сразу несколько миллионов строк, то он будет или тормозить или переполнит temp_segment. Как самостоятельный селект он используется только для проверки единичных вариантов. В боевом исполнении он встроен в parallel pipelined функцию, на вход получает от одного до сотни клиентов. С таким количеством справляется влёт.

Но я продолжаю ломать голову - нет ли другого, более элегантного решения поиска заданных комбинаций в таблице? Может кто-то решал что-то подобное?
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39459433
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Никто? ;)
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39459524
Фотография env
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarov,

multiset?
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39459628
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovЗадача - найти в списке продуктов в рамках одного дерева точные комбинации в соответствии со списком, а также продукты, для которых комбинаций не нашлись.
Код: plsql
1.
select * from product_tree full join prod_map using (prod_path)


?
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39459757
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshop
Код: plsql
1.
select * from product_tree full join prod_map using (prod_path)


?

Так получается список вообще всего, полного совпадения и неполного. Нужно только полное совпадение комбинации, например для root_id = 1 не подходит MAP_2, так как отсуствует один из четырёх продуктов этой комбинации - '|ROOT1|PROD13'.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39459956
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarov,

Цель найти root_id для каждого map, при этом root_id считается подходящим если его дети содержат все пути для конкретного map?

Если для одного map подходит более одного root_id - какой берем?

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

rpovarovПрикладное применение - миграция из одной системы в другую, комбинации продуктов из старой системы превращаются в другие комбинации в новой, на основании таблиц, составленных бизнесом и архитекторами.Так меняется иерархия или связи родитель-потомок остаются как есть, а меняются атрибуты сущности (пусть даже все атрибуты, включая имя)?
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39459998
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopЦель найти root_id для каждого map, при этом root_id считается подходящим если его дети содержат все пути для конкретного map?
Если для одного map подходит более одного root_id - какой берем?

В обратном направлении - цель найти все map_id для дерева под одним root_id.

В системе одна бизнес-служба (как её видит бизнес-аналитик) состоит из нескольких "технических" продуктов. К примеру, комбинация MAP_1 из трёх продуктов (ROOT1, PROD11 и PROD12) может быть интернет-тарифом, пусть будет INTERNET_STANDARD. А то же самое, но с ещё одним дополнительным PROD13, даёт комбинацию MAP_2, которая для бизнес-аналитика - интернет с телевидением, пусть будет INTERNET_IPTV.

Бизнес придумал обновить CRM и всё это перенести в новую систему. Там всё по другому, миграции один к одному не получится. Поэтому миграция будет проходить на уровне бизнес-служб, которые в новой системе уже сами развернутся как надо, по своим правилам.

И вот бизнес-аналитики с другими специалистами по продуктам составляют огромную Excel таблицу, в которой перечислены все существующие в старой системе комбинации продуктов и как они складываются в службы. Из такой таблицы после обработки в результате получится prod_map.

Задача - получить список MAP_1, MAP_2, ... MAP_N для каждого отдельного подписчика (будем считать, что один клиент имеет всего одно дерево продуктов, тогда root_id - это ключ, который однозначно идентифицирует клиента). Должно быть полное совпадение списка продуктов из конфигурации MAP_x, например, если есть |ROOT1 и |ROOT1|PROD12, но нет |ROOT1|PROD11, то нет и совпадения.

Продукты, для которых не нашлась комбинация, надо найти и показать бизнес-аналитикам, чтобы они решили, что с ними делать. Как вариант, чтобы выпустили новую обновлённую версию prod_map.

Т.е. на входе у нас prods, а на выходе получаем список MAP_x и информацию о тех продуктах, для которых MAP_x не нашлись. Не должно остаться ни одного забытого продукта.

dbms_photoshopПути (составленные из prod_name) в твоей иерархии неуникальные, о каком ключе может быть речь?

Ключ, наверное, не совсем правильное слово. Путь - это идентификатор, показывающий однозначное иерархическое подчинение продукта. Потому что один и тот же продукт с кодом PROD11 может находится как под ROOT1, и тогда это будет одна служба, так и под ROOT2 или ROOT3, и тогда это будет совсем другая служба и другой тариф. А вот комбинация путей (набор строчек под единым MAP_x) должна быть уникальная.

dbms_photoshopТак меняется иерархия или связи родитель-потомок остаются как есть, а меняются атрибуты сущности (пусть даже все атрибуты, включая имя)?
Меняется вообще всё. Из старой системы надо вытащить данные и поднять их на бизнес-уровень, как список служб (т.е. map_id). Который на следующем шаге превратится в исходные данные для создания этих служб в новой системе. Или в репорт качества данных, или ещё во что-нибудь...
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39460073
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovВ обратном направлении - цель найти все map_id для дерева под одним root_id.+ отсутствующие продукты из маппинга.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
select root_id,
       map_id,
       listagg(nvl2(map_prod_path, null, prod_id), ', ') within group(order by prod_id) missing_prods
  from (select pt.*,
               pm.*,
               count(pm.map_prod_path) over(partition by pt.root_id, pm.map_id) cnt_root_map
          from product_tree pt
          left join (select map_id,
                           map_group,
                           map_depth,
                           prod_path map_prod_path,
                           pos,
                           count(*) over(partition by map_id) cnt
                      from prod_map) pm partition by(pm.map_id, pm.cnt)
            on pt.prod_path = pm.map_prod_path) t0
 where cnt_root_map = cnt
 group by root_id, map_id
 order by root_id, map_id;

   ROOT_ID MAP_I MISSING_PRODS
---------- ----- ---------------
         1 MAP_1 4, 5
        10 MAP_1 31, 40, 41, 42
        10 MAP_2 40, 41, 42
        10 MAP_3 20, 31, 42
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39460074
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarov,

Учись формулировать проще и без лишней шелухи.
В твоем сообщении 8 раз встречается слово "бизнес". :)
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39460076
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshoprpovarov,

Учись формулировать проще и без лишней шелухи.
В твоем сообщении 8 раз встречается слово "бизнес". :)
Это локальный сленг, мы так называем внешнюю стихийную силу, раздающую нам указания ;)
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39460211
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshop+ отсутствующие продукты из маппинга.
Код: plsql
1.
2.
3.
4.
5.
6.
   ROOT_ID MAP_I MISSING_PRODS
---------- ----- ---------------
         1 MAP_1 4, 5
        10 MAP_1 31, 40, 41, 42
        10 MAP_2 40, 41, 42
        10 MAP_3 20, 31, 42



В этом варианте отсутствующие продукты относительно одной конкретной комбинации, а нужно относительно всех найденных. В варианте root_id = 10 бесхозным остался только продукт 42, потому что 31 используется в MAP_2, 41 в MAP_3 и т.д.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39460296
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovdbms_photoshop+ отсутствующие продукты из маппинга.
Код: plsql
1.
2.
3.
4.
5.
6.
   ROOT_ID MAP_I MISSING_PRODS
---------- ----- ---------------
         1 MAP_1 4, 5
        10 MAP_1 31, 40, 41, 42
        10 MAP_2 40, 41, 42
        10 MAP_3 20, 31, 42



В этом варианте отсутствующие продукты относительно одной конкретной комбинации, а нужно относительно всех найденных. В варианте root_id = 10 бесхозным остался только продукт 42, потому что 31 используется в MAP_2, 41 в MAP_3 и т.д.
Объяснять это явно не твой конек.
Если бы в голове была ясная картина, то и объяснить было бы просто и запрос написать.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
select root_id, map_id, prod_id
  from (select root_id,
               decode(cnt, cnt_root_map, map_id) map_id,
               prod_id,
               rank() over(partition by root_id, prod_id order by decode(cnt, cnt_root_map, 1)) rnk
          from (select pt.*,
                       pm.*,
                       count(pm.map_prod_path) over(partition by pt.root_id, pm.map_id) cnt_root_map
                  from product_tree pt
                  left join (select map_id,
                                   map_group,
                                   map_depth,
                                   prod_path map_prod_path,
                                   pos,
                                   count(*) over(partition by map_id) cnt
                              from prod_map) pm
                    on pt.prod_path = pm.map_prod_path) t0)
 where rnk = 1
 order by root_id, map_id, prod_id;

   ROOT_ID MAP_I    PROD_ID
---------- ----- ----------
         1 MAP_1          1
         1 MAP_1          2
         1 MAP_1          3
         1                4
         1                5
        10 MAP_1         10
        10 MAP_1         20
        10 MAP_1         30
        10 MAP_2         10
        10 MAP_2         20
        10 MAP_2         30
        10 MAP_2         31
        10 MAP_3         10
        10 MAP_3         30
        10 MAP_3         40
        10 MAP_3         41
        10               42

17 rows selected.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39460475
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopОбъяснять это явно не твой конек.
Если бы в голове была ясная картина, то и объяснить было бы просто и запрос написать.

Может и так. Мне казалось, что в самом первом сообщении написал понятно, плюс ещё исходники.
Комбинации могут частично пересекаться - MAP_1 и MAP_2 похожи, в MAP_2 на один продукт больше. В таких случаях при выборе используются параметры map_group и map_depth, выбирается максимальная "глубина" для совпадающей группы.

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

В любом случае твой вариант интереснее и чище. Спасибо! Вот он же с пивотом и фильтрацией по map_depth.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
select 
  root_id, map_id,
  unmapped_id, unmapped_path,
  root_pid, prod1_pid, prod2_pid, prod3_pid, prod4_pid
from 
  (select 
    root_id, map_id, unmapped_id, unmapped_path, pos, prod_id,
    rank() over (partition by root_id, map_group order by map_depth desc) group_rank
   from (select root_id,
               decode(cnt, cnt_root_map, map_id) map_id,
               decode(cnt, cnt_root_map, null, prod_id) unmapped_id,
               decode(cnt, cnt_root_map, null, prod_path) unmapped_path,
               map_group,
               map_depth,
               prod_id,
               decode(cnt, cnt_root_map, pos, null) pos,
               rank() over(partition by root_id, prod_id  order by decode(cnt, cnt_root_map, 1)) map_rank
          from (select pt.*,
                       pm.*,
                       count(pm.map_prod_path) over(partition by pt.root_id, pm.map_id) cnt_root_map
                  from product_tree pt
                  left join (select map_id,
                                   map_group,
                                   map_depth,
                                   prod_path map_prod_path,
                                   pos,
                                   count(*) over(partition by map_id) cnt
                              from prod_map) pm
                    on pt.prod_path = pm.map_prod_path)) where map_rank = 1)
          -- PIVOT result to single row for each map_id
          PIVOT ( max(prod_id) AS pid FOR (pos) IN 
            (
             'root' as root,
             'prod1' as prod1, 
             'prod2' as prod2, 
             'prod3' as prod3, 
             'prod4' as prod4
            )
          ) -- end PIVOT 
 where group_rank = 1
 order by root_id, map_id;
 




Я его ещё проверю на боевой конфигурации, потом поделюсь впечатлениями.

И за "outer join partition by" отдельное спасибо, этот вариант джойна вообще прошёл мимо меня, пойду читать документацию.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39461778
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Усложняем. Вылез вариант, когда может быть параллельно несколько одинаковых ветвей под одним корнем.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
create table prods as (
  select 1 as prod_id,  null  as parent_id, 'ROOT1'    as prod_name from dual union
  select 2 as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 3 as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 4 as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 5 as prod_id,  2     as parent_id, 'PROD121'  as prod_name from dual union
  select 6 as prod_id,  3     as parent_id, 'PROD121'  as prod_name from dual union
  select 7 as prod_id,  4     as parent_id, 'PROD121'  as prod_name from dual union
  select 8 as prod_id,  1     as parent_id, 'PROD13'   as prod_name from dual union
  select 9 as prod_id,  8     as parent_id, 'PROD121'  as prod_name from dual
);

create table product_tree as
select 
  prod_id,
  parent_id,
  connect_by_root p.prod_id                 as root_id, 
  connect_by_root p.prod_name               as root_prod, 
  p.prod_name                               as prod_name, 
  rpad(' ', (level-1)*2, ' ')||p.prod_name  as prod_name_pad, 
  sys_connect_by_path(p.prod_name, '|')     as prod_path
from prods p
start with parent_id is null 
connect by prior prod_id = parent_id;        

PROD_NAME_PAD	PROD_PATH
=============   =========
ROOT1	        |ROOT1
  PROD12	|ROOT1|PROD12
    PROD121	|ROOT1|PROD12|PROD121
  PROD12	|ROOT1|PROD12
    PROD121	|ROOT1|PROD12|PROD121
  PROD12	|ROOT1|PROD12
    PROD121	|ROOT1|PROD12|PROD121
  PROD13	|ROOT1|PROD13
    PROD121	|ROOT1|PROD13|PROD121

create table prod_map as
(
  select 'MAP_4'  map_id, 1  map_group, 1 map_depth, '|ROOT1'                 prod_path, 'root'   pos from dual union 
  select 'MAP_4'  map_id, 1  map_group, 1 map_depth, '|ROOT1|PROD12'          prod_path, 'prod1'  pos from dual union
  select 'MAP_4'  map_id, 1  map_group, 1 map_depth, '|ROOT1|PROD12|PROD121'  prod_path, 'prod2'  pos from dual
);



На выходе, соответственно, должны получиться три ветви с map_id = MAP4 (и продукты 8 и 9 как unmapped).

Уже всю голову сломал, как от себя отделить эти ветви. Если получится размножить корневой продукт отдельно к каждой ветви, повесить на всю ветвь какой-нибудь id, то потом этот id можно прописать в "... over(partition by..." рядом с root_id, и всё должно сработать.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39461818
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovУже всю голову сломал, как от себя отделить эти ветви. Если получится размножить корневой продукт отдельно к каждой ветви, повесить на всю ветвь какой-нибудь id, то потом этот id можно прописать в "... over(partition by..." рядом с root_id, и всё должно сработать.Ну ты был близок. А в чем проблема размножить?
Либо self join по like (как в примере ниже) либо строить дерево сначала от корня, а потом к корню.

Идея та же, только использовано размноженное дерево вместо оригинального (super_tree instead of product_tree) и добавлен leaf_id в логику.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
with prods as (
  select 1 as prod_id,  null  as parent_id, 'ROOT1'    as prod_name from dual union
  select 2 as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 3 as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 4 as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 5 as prod_id,  2     as parent_id, 'PROD121'  as prod_name from dual union
  select 6 as prod_id,  3     as parent_id, 'PROD121'  as prod_name from dual union
  select 7 as prod_id,  4     as parent_id, 'PROD121'  as prod_name from dual union
  select 8 as prod_id,  1     as parent_id, 'PROD13'   as prod_name from dual union
  select 9 as prod_id,  8     as parent_id, 'PROD121'  as prod_name from dual
),
product_tree as (
select
  prod_id,
  parent_id,
  connect_by_root p.prod_id                 as root_id,
  connect_by_root p.prod_name               as root_prod,
  p.prod_name                               as prod_name,
  rpad(' ', (level-1)*2, ' ')||p.prod_name  as prod_name_pad,
  sys_connect_by_path(p.prod_name, '|')     as prod_path,
  --
  sys_connect_by_path(p.prod_id, '|')       as unique_path,
  connect_by_isleaf                         as isleaf
from prods p
start with parent_id is null
connect by prior prod_id = parent_id),
super_tree as (
select pt1.prod_id leaf_id, pt2.*
  from product_tree pt1
  left join product_tree pt2
    on pt1.unique_path like pt2.unique_path || '%'
 where pt1.isleaf = 1),
prod_map as
(
  select 'MAP_4'  map_id, 1  map_group, 1 map_depth, '|ROOT1'                 prod_path, 'root'   pos from dual union
  select 'MAP_4'  map_id, 1  map_group, 1 map_depth, '|ROOT1|PROD12'          prod_path, 'prod1'  pos from dual union
  select 'MAP_4'  map_id, 1  map_group, 1 map_depth, '|ROOT1|PROD12|PROD121'  prod_path, 'prod2'  pos from dual
)
select root_id, leaf_id, map_id, prod_id, prod_path
  from (select root_id,
               leaf_id,
               decode(cnt, cnt_root_map, map_id) map_id,
               prod_id,
               prod_path,
               rank() over(partition by root_id, prod_id order by decode(cnt, cnt_root_map, 1)) rnk
          from (select pt.*,
                       pm.*,
                       count(pm.map_prod_path) over(partition by pt.root_id, pt.leaf_id, pm.map_id) cnt_root_map
                  from super_tree pt
                  left join (select map_id,
                                   map_group,
                                   map_depth,
                                   prod_path map_prod_path,
                                   pos,
                                   count(*) over(partition by map_id) cnt
                              from prod_map) pm
                    on pt.prod_path = pm.map_prod_path) t0)
 where rnk = 1
 order by root_id, leaf_id, map_id, prod_id;

   ROOT_ID    LEAF_ID MAP_I    PROD_ID PROD_PATH
---------- ---------- ----- ---------- ------------------------------
         1          5 MAP_4          1 |ROOT1
         1          5 MAP_4          2 |ROOT1|PROD12
         1          5 MAP_4          5 |ROOT1|PROD12|PROD121
         1          6 MAP_4          1 |ROOT1
         1          6 MAP_4          3 |ROOT1|PROD12
         1          6 MAP_4          6 |ROOT1|PROD12|PROD121
         1          7 MAP_4          1 |ROOT1
         1          7 MAP_4          4 |ROOT1|PROD12
         1          7 MAP_4          7 |ROOT1|PROD12|PROD121
         1          9                8 |ROOT1|PROD13
         1          9                9 |ROOT1|PROD13|PROD121

11 rows selected.

...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39461823
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopНу ты был близок. А в чем проблема размножить?
Либо self join по like (как в примере ниже) либо строить дерево сначала от корня, а потом к корню.


Проблема, как всегда, в ДНК :)
Я раньше подобные задачи решал нахрапом черед PL/SQL, но практика показала, что чем больше запихнуть в SQL (в разумных пределах), тем лучше и быстрее в результате всё работает. Но мозги перестраивать силком надо...

Спасибо за пример! Завтра погоняю на работе, может ещё что найду интересного.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39461826
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovdbms_photoshopНу ты был близок. А в чем проблема размножить?
Либо self join по like (как в примере ниже) либо строить дерево сначала от корня, а потом к корню.


Проблема, как всегда, в ДНК :)
Я раньше подобные задачи решал нахрапом черед PL/SQL, но практика показала, что чем больше запихнуть в SQL (в разумных пределах), тем лучше и быстрее в результате всё работает. Но мозги перестраивать силком надо...

Спасибо за пример! Завтра погоняю на работе, может ещё что найду интересного.Это хорошо, что ты перестал заниматься глупостями. Я закончил свое исследование разумных пределов SQL vs PL/SQL, надеюсь до конца недели выложить. :)
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39461829
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopЭто хорошо, что ты перестал заниматься глупостями. Я закончил свое исследование разумных пределов SQL vs PL/SQL, надеюсь до конца недели выложить. :)
Была одна задачка, которая чистым SQL не решалась совсем или решалась с огромным геморроем и ограничениями. Тоже обход дерева, но нет прямой иерархии, она строится на ходу в зависимости от того, что нашлось в каждой ветке. Конфигурация была написана для Java-кода в бэкенде, и он там успешно работает. Потребовалось его повторить, но прямо над базой данных. Обход дерева рекурсией в PL/SQL, но там, где ситуация позволяет, скармливаю таблицы в SQL. В результате довольно быстро работает (если распараллелить), и побочным эффектом вывод в логи или на экран всего построенного дерева с комментариями :)
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39461835
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovБыла одна задачка, которая чистым SQL не решалась совсем или решалась с огромным геморроем и ограничениями. Тоже обход дерева, но нет прямой иерархии, она строится на ходу в зависимости от того, что нашлось в каждой ветке. Конфигурация была написана для Java-кода в бэкенде, и он там успешно работает. Потребовалось его повторить, но прямо над базой данных. Обход дерева рекурсией в PL/SQL, но там, где ситуация позволяет, скармливаю таблицы в SQL. В результате довольно быстро работает (если распараллелить), и побочным эффектом вывод в логи или на экран всего построенного дерева с комментариями :)Описывая свой "любимый говнокод" своими же ощущениями наивно полагать встретить понимание.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39461862
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovнет прямой иерархии, она строится на ходу в зависимости от того, что нашлось в каждой веткеЭто наводит на мысль, что на SQL было бы уместнее решать с помощью rec with чем connect by.
А я имею в виду, что есть случаи, когда PL/SQL предпочтительнее базового SQL без ухищрений.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39462384
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopИдея та же, только использовано размноженное дерево вместо оригинального (super_tree instead of product_tree) и добавлен leaf_id в логику.

Если в дереве и prod_map попадается комбинация, где несколько последних в цепочке продуктов на одном уровне

Код: plaintext
1.
2.
3.
|ROOT2
|ROOT2|PROD12
|ROOT2|PROD12|PROD121
|ROOT2|PROD12|PROD122

но при этом нет параллельных ветвей, то получается интересно :)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
ROOT_ID	LEAF_ID	MAP_ID	PROD_ID	PROD_PATH
100	120		100	|ROOT2
100	120		110	|ROOT2|PROD12
100	120		120	|ROOT2|PROD12|PROD121
100	130		100	|ROOT2
100	130		110	|ROOT2|PROD12
100	130		130	|ROOT2|PROD12|PROD122

Два "хвоста" образовали каждый свою ветку по leaf_id. При этом, если присутствуют параллельные ветки, то всё в порядке
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
ROOT_ID	LEAF_ID	MAP_ID	PROD_ID	PROD_PATH
1	60	MAP_4	1	|ROOT1
1	60	MAP_4	3	|ROOT1|PROD12
1	60	MAP_4	6	|ROOT1|PROD12|PROD121
1	60	MAP_4	60	|ROOT1|PROD12|PROD122
1	70	MAP_4	1	|ROOT1
1	70	MAP_4	4	|ROOT1|PROD12
1	70	MAP_4	7	|ROOT1|PROD12|PROD121
1	70	MAP_4	70	|ROOT1|PROD12|PROD122

Немного поправил product_tree и super_tree, размножаю только множественные случаи
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
product_tree as (
select
  prod_id,
<...skip...>
  connect_by_isleaf                         as isleaf,
  --
  count(*) over (partition by sys_connect_by_path(p.prod_name, '|')) as qty
from prods p
start with parent_id is null
connect by prior prod_id = parent_id),
super_tree as (
  select -1 leaf_id, pt1.*
    from product_tree pt1
   where pt1.qty = 1 
  union all  
  select pt1.prod_id leaf_id, pt2.*
    from product_tree pt1
    left join product_tree pt2
      on pt1.unique_path like pt2.unique_path || '%' 
   where pt1.qty > 1 and pt1.isleaf = 1 
),



Результат
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
ROOT_ID	LEAF_ID	MAP_ID	PROD_ID	PROD_PATH
1	60	MAP_4	1	|ROOT1
1	60	MAP_4	3	|ROOT1|PROD12
1	60	MAP_4	6	|ROOT1|PROD12|PROD121
1	60	MAP_4	60	|ROOT1|PROD12|PROD122
1	70	MAP_4	1	|ROOT1
1	70	MAP_4	4	|ROOT1|PROD12
1	70	MAP_4	7	|ROOT1|PROD12|PROD121
1	70	MAP_4	70	|ROOT1|PROD12|PROD122
100	-1	MAP_5	100	|ROOT2
100	-1	MAP_5	110	|ROOT2|PROD12
100	-1	MAP_5	120	|ROOT2|PROD12|PROD121
100	-1	MAP_5	130	|ROOT2|PROD12|PROD122

Весь код
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
 with prods as (
  select 1  as prod_id,  null  as parent_id, 'ROOT1'    as prod_name from dual union
  select 2  as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 3  as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 4  as prod_id,  1     as parent_id, 'PROD12'   as prod_name from dual union
  select 5  as prod_id,  2     as parent_id, 'PROD121'  as prod_name from dual union
  select 6  as prod_id,  3     as parent_id, 'PROD121'  as prod_name from dual union
  select 7  as prod_id,  4     as parent_id, 'PROD121'  as prod_name from dual union
  --
  select 50 as prod_id,  2     as parent_id, 'PROD122'  as prod_name from dual union
  select 60 as prod_id,  3     as parent_id, 'PROD122'  as prod_name from dual union
  select 70 as prod_id,  4     as parent_id, 'PROD122'  as prod_name from dual union
  --
  select 8  as prod_id,  1     as parent_id, 'PROD13'   as prod_name from dual union
  select 9  as prod_id,  8     as parent_id, 'PROD121'  as prod_name from dual union
  --
  select 100 as prod_id,  null   as parent_id, 'ROOT2'    as prod_name from dual union
  select 110 as prod_id,  100    as parent_id, 'PROD12'   as prod_name from dual union
  select 120 as prod_id,  110    as parent_id, 'PROD121'  as prod_name from dual union
  select 130 as prod_id,  110    as parent_id, 'PROD122'  as prod_name from dual 
),
product_tree as (
select
  prod_id,
  parent_id,
  connect_by_root p.prod_id                 as root_id,
  connect_by_root p.prod_name               as root_prod,
  p.prod_name                               as prod_name,
  rpad(' ', (level-1)*2, ' ')||p.prod_name  as prod_name_pad,
  sys_connect_by_path(p.prod_name, '|')     as prod_path,
  --
  sys_connect_by_path(p.prod_id, '|')       as unique_path,
  connect_by_isleaf                         as isleaf,
  --
  count(*) over (partition by sys_connect_by_path(p.prod_name, '|')) as qty
from prods p
start with parent_id is null
connect by prior prod_id = parent_id),
super_tree as (
  select -1 leaf_id, pt1.*
    from product_tree pt1
   where pt1.qty = 1 
  union all  
  select pt1.prod_id leaf_id, pt2.*
    from product_tree pt1
    left join product_tree pt2
      on pt1.unique_path like pt2.unique_path || '%' 
   where pt1.qty > 1 and pt1.isleaf = 1 
),
prod_map as
(
  select 'MAP_4'  map_id, 1  map_group, 2 map_depth, '|ROOT1'                 prod_path, 'root'   pos from dual union
  select 'MAP_4'  map_id, 1  map_group, 2 map_depth, '|ROOT1|PROD12'          prod_path, 'prod1'  pos from dual union
  select 'MAP_4'  map_id, 1  map_group, 2 map_depth, '|ROOT1|PROD12|PROD121'  prod_path, 'prod2'  pos from dual union 
  select 'MAP_4'  map_id, 1  map_group, 2 map_depth, '|ROOT1|PROD12|PROD122'  prod_path, 'prod3'  pos from dual union
  --
  select 'MAP_5'  map_id, 1  map_group, 2 map_depth, '|ROOT2'                 prod_path, 'root'   pos from dual union
  select 'MAP_5'  map_id, 1  map_group, 2 map_depth, '|ROOT2|PROD12'          prod_path, 'prod1'  pos from dual union
  select 'MAP_5'  map_id, 1  map_group, 2 map_depth, '|ROOT2|PROD12|PROD121'  prod_path, 'prod2'  pos from dual union 
  select 'MAP_5'  map_id, 1  map_group, 2 map_depth, '|ROOT2|PROD12|PROD122'  prod_path, 'prod3'  pos from dual
)
select root_id, leaf_id, map_id, prod_id, prod_path
  from (select root_id,
               leaf_id,
               decode(cnt, cnt_root_map, map_id) map_id,
               prod_id,
               prod_path,
               rank() over(partition by root_id, prod_id order by decode(cnt, cnt_root_map, 1)) rnk
          from (select pt.*,
                       pm.*,
                       count(pm.map_prod_path) over(partition by pt.root_id, pt.leaf_id, pm.map_id) cnt_root_map
                  from super_tree pt
                  left join (select map_id,
                                   map_group,
                                   map_depth,
                                   prod_path map_prod_path,
                                   pos,
                                   count(*) over(partition by map_id) cnt
                              from prod_map) pm
                    on pt.prod_path = pm.map_prod_path) t0)
 where rnk = 1
 order by root_id, leaf_id, map_id, prod_id;

...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39462412
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovДва "хвоста" образовали каждый свою ветку по leaf_id. При этом, если присутствуют параллельные ветки, то всё в порядке
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
ROOT_ID	LEAF_ID	MAP_ID	PROD_ID	PROD_PATH
1	60	MAP_4	1	|ROOT1
1	60	MAP_4	3	|ROOT1|PROD12
1	60	MAP_4	6	|ROOT1|PROD12|PROD121
1	60	MAP_4	60	|ROOT1|PROD12|PROD122
1	70	MAP_4	1	|ROOT1
1	70	MAP_4	4	|ROOT1|PROD12
1	70	MAP_4	7	|ROOT1|PROD12|PROD121
1	70	MAP_4	70	|ROOT1|PROD12|PROD122

Откуда тут взялось 8 строк вместо шести?? Выше в примере два листа грубины три. 3*2=6.

rpovarovНемного поправил product_tree и super_tree, размножаю только множественные случаиКакое отношение этот фикс имеет к реальной жизни?
Или, говоря твоим сленгом, какое бизнес правило говорит, что надо "размножать только множественные"?
Больше похоже либо на костыль либо для кривых данных либо от недопонимания принципа работы.

Это как некоторые разработчики которые не хотят вникать до конца почему запрос возвращает дубли просто засовывают в него distinct и не парятся.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39462487
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshop,

Этих строчек не было в исходном примере. Я проверял скрипт на боевых таблицах, и нашёл комбинацию, при которой вылезает косяк. Оформил это в виде нового примера и запостил вместе со своим костылём.

То, что в старой системе было в одном экземпляре, в новой тоже будет в одном. Например, тариф. Если было несколько одинаковых веток, то и в новой тоже будет столько же. Например, несколько сим-карт к одному тарифу.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39462510
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rpovarovdbms_photoshop,

Этих строчек не было в исходном примере. Я проверял скрипт на боевых таблицах, и нашёл комбинацию, при которой вылезает косяк. Оформил это в виде нового примера и запостил вместе со своим костылём.

То, что в старой системе было в одном экземпляре, в новой тоже будет в одном. Например, тариф. Если было несколько одинаковых веток, то и в новой тоже будет столько же. Например, несколько сим-карт к одному тарифу.Я не говорил про исходный пример. Я ссылался на последнее сообщение.
Еще раз, откуда у тебя взялось 8 вместо 6.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
with prods as (
  select 100 as prod_id,  null  as parent_id, 'ROOT1'    as prod_name from dual union
  select 110 as prod_id,  100   as parent_id, 'PROD12'   as prod_name from dual union
  select 120 as prod_id,  110   as parent_id, 'PROD121'  as prod_name from dual union
  select 130 as prod_id,  110   as parent_id, 'PROD122'  as prod_name from dual
),
product_tree as (
select
  prod_id,
  parent_id,
  connect_by_root p.prod_id                 as root_id,
  connect_by_root p.prod_name               as root_prod,
  p.prod_name                               as prod_name,
  rpad(' ', (level-1)*2, ' ')||p.prod_name  as prod_name_pad,
  sys_connect_by_path(p.prod_name, '|')     as prod_path,
  --
  sys_connect_by_path(p.prod_id, '|')       as unique_path,
  connect_by_isleaf                         as isleaf
from prods p
start with parent_id is null
connect by prior prod_id = parent_id),
super_tree as (
select pt1.prod_id leaf_id, pt2.*
  from product_tree pt1
  left join product_tree pt2
    on pt1.unique_path like pt2.unique_path || '%'
 where pt1.isleaf = 1)
select * from super_tree;



Касательно костылей, нормальный подход как раз отличается от костыля тем,
что данные приводятся в нужную форму до применения логики.
А говнокод - это когда начинает что-то вылазить неожиданное и не учтенное во входных данных,
а разработчик пытается от этого избавиться в процессе.
...
Рейтинг: 0 / 0
Поиск комбинаций строк в таблице
    #39462529
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshop,

В сообщении 20521106 , где начали решать проблему одинаковых ветвей, пример был упрощённый, из трёх продуктов. Моя ошибка. Если бы взял конфигурацию для четырёх продуктов из самого первого сообщения - было бы правильнее. "Хорошая мысля приходит опосля..."
...
Рейтинг: 0 / 0
25 сообщений из 40, страница 1 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Поиск комбинаций строк в таблице
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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