Volokh
Volokh

Reputation: 390

Recursive Iteration in Oracle

I have a table like that:

 +----+-----+------+
 | id | ord | test |
 +----+-----+------+
 |  1 |   1 | A    |
 |  1 |   2 | B    |
 |  1 |   3 | C    |
 |  2 |   1 | B    |
 |  2 |   2 | C    |
 +----+-----+------+

(Here is some code for creating the data)

drop table temp_test;
create table temp_test (id varchar(20), ord varchar(20), test varchar(20));
insert into temp_test (id,ord,test) values ('1','1','A');
insert into temp_test (id,ord,test) values ('1','2','B');
insert into temp_test (id,ord,test) values ('1','3','C');
insert into temp_test (id,ord,test) values ('2','1','B');
insert into temp_test (id,ord,test) values ('2','2','C');
commit;

How could I get the following result?

+----+-----+-------+
| id | ord | test  |
+----+-----+-------+
|  1 |   1 | A     |
|  1 |   2 | A_B   |
|  1 |   3 | A_B_C |
|  2 |   1 | B     |
|  2 |   2 | B_C   |
+----+-----+-------+

I have tried using LAG(), something like:

  select CONCAT(lag(TEST) over (partition by ID order by ord),TEST) AS TEST from temp_test;

but it does not work recursively.

This code works:

SELECT 
R1.*,
(   SELECT  LISTAGG(test, ';') WITHIN GROUP (ORDER BY ord)
    FROM    temp_test R2
    WHERE   R1.ord >= R2.ord
    AND     R1.ID = R2.ID
    GROUP BY ID
) AS WTR_KEYWORD_1
FROM temp_test R1
ORDER BY id, ord;

but it is not performant enough for a larger data set.

Upvotes: 1

Views: 200

Answers (2)

Kaushik Nayak
Kaushik Nayak

Reputation: 31656

Some say the Hierarchical queries are outdated, but they generally perform far better than recursive CTE

SELECT id,
       ord,
       LTRIM(sys_connect_by_path(test,'_'),'_') as test
FROM temp_test r2 START WITH ord = 1 -- use MIN() to get this if it's not always 1
CONNECT BY PRIOR id = id AND ord = PRIOR ord + 1;

Demo

Upvotes: 1

George Joseph
George Joseph

Reputation: 5922

you can make use of recursive cte to achieve this

with cte(id,ord,test,concat_val) 
  as (select id,ord,test,test as concat_val
       from temp_test
       where ord=1
      union all
      select a.id,a.ord,a.test,b.concat_val||'_'||a.test
        from temp_test a
        join cte b
          on a.id=b.id
         and a.ord=b.ord+1 
      )
select * from cte order by id,ord

Demo here

https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=78baa20f7f364e653899caf63ce7ada2

Upvotes: 1

Related Questions