Reputation: 1167
This may seem straightforward, but I couldn't find the answer in docs.
As with nested tables, we can use TABLE()
with COLUMN_VALUE
pseudocolumn for varrays.
create or replace type NUMBER_ARRAY as VARRAY(10) of NUMBER;
create table TAB_WITH_ARRAY(
ID NUMBER,
VALS NUMBER_ARRAY)
insert into TAB_WITH_ARRAY
select 1, NUMBER_ARRAY(1,2)
from dual
union all
select 2, NUMBER_ARRAY(1,2,3,4,5)
from dual
select t.id, c.column_value
from TAB_WITH_ARRAY t,
table(t.vals) c
However, unlike nested tables, VARRAY
is an ordered collection type, and I want to preserve that order. Is there a way to get not only value but also index of each element in SQL?
Yes, in my tests the order of output was right and I could just use ROW_NUMBER
with PARTITION BY
primary key of my main table to generate indexes, but experience taught me not rely on ordering unless it was manually specified.
So is there a built-in way to access indexes of elements in array?
Upvotes: 3
Views: 1361
Reputation: 167962
Use the ROW_NUMBER()
analytic function:
SELECT t.id,
c.COLUMN_VALUE,
ROW_NUMBER() OVER ( PARTITION BY t.ROWID ORDER BY ROWNUM ) AS idx
FROM TAB_WITH_ARRAY t
CROSS JOIN
TABLE( t.vals ) c
Or, from Oracle 12c, use OUTER APPLY
and ROWNUM
:
SELECT t.id,
v.*
FROM tab_with_array t
OUTER APPLY (
SELECT v.COLUMN_VALUE,
ROWNUM AS idx
FROM TABLE( t.vals ) v
) v
Which, for your sample data, both outputs:
ID | COLUMN_VALUE | IDX -: | -----------: | --: 1 | 1 | 1 1 | 2 | 2 2 | 1 | 1 2 | 2 | 2 2 | 3 | 3 2 | 4 | 4 2 | 5 | 5
db<>fiddle here
Upvotes: 2