Reputation: 16400
I'm playing around with array support in Oracle and hit a roadblock regarding array access within a SQL query. I'm using the following schema:
create type smallintarray as varray(10) of number(3,0);
create table tbl (
id number(19,0) not null,
the_array smallintarray,
primary key (id)
);
What I would like to do is get the id and the first element i.e. at index 1 of the array. In PostgreSQL I could write select id, the_array[1] from tbl t
but I don't see how I could do that with Oracle. I read that array access by index is only possible in PL/SQL, which would be fine if I could return a "decorated cursor" to achieve the same result through JDBC, but I don't know if that's possible.
DECLARE
c1 SYS_REFCURSOR;
varr smallintarray2;
BEGIN
OPEN c1 FOR SELECT t.id, t.THE_ARRAY from tbl t;
-- SELECT t.THE_ARRAY INTO varr FROM table_with_enum_arrays2 t;
-- return a "decorated cursor" with varr(1) at select item position 1
dbms_sql.return_result(c1);
END;
Upvotes: 0
Views: 2003
Reputation: 4076
You can use the undocumented function named SYS_OP_CEG
to do that in Oracle SQL:
SELECT SYS_OP_CEG
( sys.odcivarchar2list('Dave','Dee','Dozy','Beaky','Mick','Titch')
, 3 ) AS third_item
FROM dual;
SYS_OP_CEG
takes a varray and a one-based index as parameters. The example above uses a varray of varchar2
and prints Dozy
which is the third element.
It works with numbers too:
SELECT SYS_OP_CEG
( sys.odcinumberlist(5, 10, 84, -12, 9999, 6666)
, 3 ) AS third_item
FROM dual;
Yes it's less straightforward than PostgreSQL and surprisingly, it produces an Oracle error ORA-31009 when you pass a negative integer.
P.S: I've just tested with Oracle 19 but it's expected to work with Oracle 9.2 and above.
Upvotes: 0
Reputation:
You can do this in plain SQL; it's not pretty, but it does work. You would prefer that Oracle had syntax to hide this from the programmer (and perhaps it does, at least in the most recent versions; I am still stuck at 12.2).
select t.id, q.array_element
from tbl t cross apply
( select column_value as array_element,
rownum as ord
from table(the_array)
) q
where ord = 1
;
EDIT If order of generating the elements through the table
operator is a concern, you could do something like this (in Oracle 12.1 and higher; otherwise the function can't be part of the query itself, but it can be defined on its own):
with
function select_element(arr smallintarray, i integer)
return number
as
begin
return arr(i);
end;
select id, select_element(the_array, 1) as the_array_1
from tbl
/
Upvotes: 2
Reputation: 4129
First of all, please don't do that on production. Use tables instead of storing arrays within a table.
Answer to your question is to use column as a table source
SELECT t.id, ta.*
from tbl t,
table(t.THE_ARRAY) ta
order by column_value
-- offset 1 row -- in case if sometime you'll need to skip a row
fetch first 1 row only;
UPD: as for ordering the array I can only say playing with 2asc/desc" parameters provided me with results I've expected - it has been ordered ascending or descending.
UPD2: found a cool link to description of performance issues might happen
Upvotes: 1