Это интересный вопрос, похожий на этот SO . Вы можете построить запрос, используя тот же подход:
SQL> WITH orders AS (
2 SELECT 'ORDER1' ord, 'A' cont FROM dual
3 UNION ALL SELECT 'ORDER1' , 'B' FROM dual
4 UNION ALL SELECT 'ORDER2' , 'B' FROM dual
5 UNION ALL SELECT 'ORDER2' , 'C' FROM dual
6 UNION ALL SELECT 'ORDER3' , 'C' FROM dual
7 UNION ALL SELECT 'ORDER3' , 'D' FROM dual
8 UNION ALL SELECT 'ORDER4' , 'E' FROM dual
9 )
10 SELECT ord, MIN(grp) "group" /*, cont*/
11 FROM (SELECT connect_by_root(ord) ord,
12 connect_by_root(cont) cont,
13 cont grp
14 FROM orders
15 CONNECT BY NOCYCLE(cont = PRIOR cont
16 OR ord = PRIOR ord))
17 GROUP BY ord /*, cont*/
18 ORDER BY ord, MIN(grp);
ORD group
------ -----
ORDER1 A
ORDER2 A
ORDER3 A
ORDER4 E
Обновление
Я попытался сгенерировать еще несколько данных, чтобы воспроизвести вашу проблему с производительностью. При наличии только тысячи заказов запрос действительно не возвращается своевременно.
Я пытался настроить запрос с помощью предложений CONNECT BY и START WITH, но не смог улучшить производительность. Моя следующая идея состояла в том, чтобы отобразить данные в более традиционном иерархическом представлении:
SQL> SELECT o1.ord "order", o2.ord "is connected to"
2 FROM orders o1
3 JOIN orders o2 ON o1.cont = o2.cont
4 AND o1.ord < o2.ord;
order is connected to
------ ---------------
ORDER1 ORDER2
ORDER2 ORDER3
Это, в свою очередь, основа для следующего запроса, который довольно хорошо работал в моем наборе тестовых данных:
SQL> SELECT o.ord, nvl(MIN(connexions.grp), o.ord) grp
2 FROM orders o
3 LEFT JOIN (SELECT connect_by_root(ord1) grp, ord2
4 --, sys_connect_by_path(ord1, '->')
5 FROM (SELECT o1.ord ord1, o2.ord ord2
6 FROM orders o1
7 JOIN orders o2 ON o1.cont = o2.cont
8 AND o1.ord < o2.ord)
9 CONNECT BY PRIOR ord2 = ord1
10 ORDER BY 1, 2) connexions ON o.ord = connexions.ord2
11 GROUP BY o.ord
12 order by 1,2;
ORD GRP
------ ------
ORDER1 ORDER1
ORDER2 ORDER1
ORDER3 ORDER1
ORDER4 ORDER4
Я использовал следующий запрос для заполнения моего набора данных (1200 строк):
CREATE TABLE orders AS
SELECT 'ORDER' || to_char(dbms_random.VALUE(0, 1000), 'fm000000') ord,
to_char(dbms_random.VALUE(0, 800), 'fm000000') cont
FROM dual
CONNECT BY LEVEL <= 1200;