In the following example I create a VARRAY with 3 items.
TEST@XE> select t1, t2.* from
2 (select \'X\' as t1 from dual UNION select \'Y\' from dual) t1
I'm wondering why nobody came up with this, so I'm answering my own question
select t1, t2.* from
(select 'X' as t1 from dual UNION select 'Y' from dual) t1,
(select ROWNUM rn, COLUMN_VALUE from table (sys.odcivarchar2list('a', 'b', 'c'))) t2
T1 RN COLUMN_VALUE
--- ---------- --------------------
X 1 a
X 2 b
X 3 c
Y 1 a
Y 2 b
Y 3 c
The question remains however, whether this is actually guaranteed to work 100%
select t1, row_number() over ( partition by t1 order by t1), t2.* from
(select 'X' as t1 from dual UNION select 'Y' from dual) t1,
table (sys.odcivarchar2list('a', 'b', 'c')) t2;
As far as I know there is no pure SQL solution that is guaranteed to work. You'll probably need to create a PL/SQL function to convert the VARRAY of VARCHAR2 into a VARRAY of objects.
Even for the PL/SQL solution below, it's difficult to say that it's guaranteed to work. I can't find anything in the PL/SQL Language Reference that explicitly says the order of items in the constructor will always match the index order. But the examples imply that the order is preserved, and if it weren't true it would cause all kinds of weird bugs that I probably would have encountered by now..
Note that my example may not work for nested tables. From the manual:
"When you store and retrieve a varray from the database, its indexes and element order remain stable." ... "The indexes and row order of a nested table might not remain stable as you store and retrieve the nested table from the database."
SQL> create or replace type varchar2_with_index as object
2 (
3 id number,
4 value varchar2(4000)
5 );
6 /
Type created.
SQL> create or replace type varchar2_with_index_varray as
2 varray(32767) of varchar2_with_index;
3 /
Type created.
SQL> create or replace function add_index(p_list in sys.ODCIVarchar2List
2 ) return varchar2_with_index_varray as
3 v_new_list varchar2_with_index_varray := varchar2_with_index_varray();
4 begin
5 for i in 1 .. p_list.count loop
6 v_new_list.extend;
7 v_new_list(v_new_list.count) := varchar2_with_index(i, p_list(i));
8 end loop;
9 return v_new_list;
10 end;
11 /
Function created.
SQL> column value format a6
SQL> select t1, t2.* from
2 (select 'X' as t1 from dual UNION select 'Y' from dual) t1,
3 table (add_index(sys.odcivarchar2list('a', 'b', 'c'))) t2;
T ID VALUE
- ---------- ------
X 1 a
X 2 b
X 3 c
Y 1 a
Y 2 b
Y 3 c
6 rows selected.