19

In Oracle, I would sometimes like to create constructs such as these ones

SELECT * FROM TABLE(STRINGS('a', 'b', 'c'))
SELECT * FROM TABLE(NUMBERS(1, 2, 3))

Obviously, I can declare my own types for the above. I can choose between TABLE and VARRAY. For example:

CREATE TYPE STRINGS AS TABLE OF VARCHAR2(100);
CREATE TYPE NUMBERS AS VARRAY(100) OF NUMBER(10);

In this particular case, another solution is to write things like

SELECT 'a' FROM DUAL UNION ALL
SELECT 'b' FROM DUAL UNION ALL
SELECT 'c' FROM DUAL

But I may have more complex examples where I will really need a TABLE / VARRAY type. So what if my SQL is running on an unknown system where I cannot create types because I may not have the necessary grants?

So my question is: Does Oracle know "anonymous" TABLE / VARRAY types that are available on any Oracle instance? Similar to Postgres / H2 / HSQLDB's simple ARRAY types?

UPDATE: I am mostly running this SQL from Java, if this is relevant. No need to explain PL/SQL to me, I'm really just looking for anonymous SQL array types (i.e. "anonymous" standalone stored types). If they don't exist at all, the answer is NO

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • Have you considered using PLSQL? – Rene Jan 09 '12 at 08:20
  • @Rene: "*My SQL is running on an unknown system where I cannot create types*", so I cannot use PL/SQL, as I may not be able to create the necessary types / functions... unless you mean anonymous PL/SQL blocks? How would you solve this generally, then? – Lukas Eder Jan 09 '12 at 08:21

3 Answers3

21

Providing you're not scared of explicitly referencing the SYS schema there are a few. Here are some I use quite often (well odcivarchar2list not so much, as it chews up a lot of memory: for strings I prefer dbms_debug_vc2coll).

SQL> desc sys.odcinumberlist
 sys.odcinumberlist VARRAY(32767) OF NUMBER

SQL> desc sys.odcivarchar2list
 sys.odcivarchar2list VARRAY(32767) OF VARCHAR2(4000)

SQL> desc sys.ODCIDATELIST
 sys.ODCIDATELIST VARRAY(32767) OF DATE

SQL> desc sys.dbms_debug_vc2coll
 sys.dbms_debug_vc2coll TABLE OF VARCHAR2(1000)

SQL> 

However, if those aren't sufficient for your needs run this query to find some more:

select type_name
       , owner
from all_types
where typecode = 'COLLECTION'
and owner != user
/

Of course, this result will vary from database to database. For instance a lot of the colllections on my database are owned by XDB and not every system will have that installed. The four I listed at the the top of this answer should be available on every database since 9iR2 (and perhaps early) although they are not always documented in earlier versions.


"Note that ALL_COLL_TYPES seems to be an even better dictionary view to find appropriate types"

That's a good point. We can also filter on COLL_TYPE to winnow out the VARRAYs. That view was introduced into 10g whereas ALL_TYPES was available on 9i. As with most things Oracle, the later the version the more functionality it has.

APC
  • 144,005
  • 19
  • 170
  • 281
  • That is a quite interesting approach. Not what I had in mind, but definitely clever! :-) Note that `ALL_COLL_TYPES` seems to be an even better dictionary view to find appropriate types (you can filter on `ELEM_TYPE_NAME = 'VARCHAR2'` for instance... – Lukas Eder Jan 09 '12 at 09:51
  • **accepted answer**: Short of true anonymous types, I guess this is as good as it gets. Thanks! – Lukas Eder Jan 09 '12 at 10:02
  • I have added a query and its results [here](http://stackoverflow.com/questions/8785459/anonymous-table-or-varray-type-in-oracle/8786893#8786893) to document what I get when querying for `ALL_COLL_TYPES`... – Lukas Eder Jan 09 '12 at 10:21
19

SQL table and varray types

An interesting solution was given by user APC here. For future readers of this question, it may be interesting to see that this query provides what I'm really interested in:

select coll_type, elem_type_name, type_name, length, upper_bound
from all_coll_types
where owner = 'SYS'
and elem_type_name IN ('VARCHAR2', 'NUMBER')
order by coll_type, elem_type_name, type_name;

Resulting in (in Oracle 11g):

+-------------+--------------+----------------------+------+-----------+
|COLL_TYPE    |ELEM_TYPE_NAME|TYPE_NAME             |LENGTH|UPPER_BOUND|
+-------------+--------------+----------------------+------+-----------+
|TABLE        |NUMBER        |KU$_OBJNUMSET         |{null}|     {null}|
|TABLE        |NUMBER        |KU$_XMLCOLSET_T       |{null}|     {null}|
|TABLE        |NUMBER        |ORA_MINING_NUMBER_NT  |{null}|     {null}|
|TABLE        |VARCHAR2      |DBMS_AW$_COLUMNLIST_T |   100|     {null}|
|TABLE        |VARCHAR2      |DBMS_DEBUG_VC2COLL    |  1000|     {null}|
|TABLE        |VARCHAR2      |HSBLKNAMLST           |    30|     {null}|
|TABLE        |VARCHAR2      |KU$_VCNT              |  4000|     {null}|
|TABLE        |VARCHAR2      |ORA_MINING_VARCHAR2_NT|  4000|     {null}|
|VARYING ARRAY|NUMBER        |AWRRPT_NUM_ARY        |{null}|         30|
|VARYING ARRAY|NUMBER        |JDM_NUM_VALS          |{null}|        999|
|VARYING ARRAY|NUMBER        |ODCIGRANULELIST       |{null}|      65535|
|VARYING ARRAY|NUMBER        |ODCINUMBERLIST        |{null}|      32767|
|VARYING ARRAY|NUMBER        |SQL_OBJECTS           |{null}|       2000|
|VARYING ARRAY|NUMBER        |TABLESPACE_LIST       |{null}|      64000|
|VARYING ARRAY|VARCHAR2      |AQ$_JMS_NAMEARRAY     |   200|       1024|
|VARYING ARRAY|VARCHAR2      |AQ$_MIDARRAY          |    32|       1024|
|VARYING ARRAY|VARCHAR2      |AWRRPT_VCH_ARY        |    80|         30|
|VARYING ARRAY|VARCHAR2      |DBMSOUTPUT_LINESARRAY | 32767| 2147483647|
|VARYING ARRAY|VARCHAR2      |DBMS_XS_ROLELIST      |  1024|       4096|
|VARYING ARRAY|VARCHAR2      |FLASHBACKTBLIST       |    30|        100|
|VARYING ARRAY|VARCHAR2      |HSBLKVALARY           |  4000|        250|
|VARYING ARRAY|VARCHAR2      |JDM_ATTR_NAMES        |    60|        999|
|VARYING ARRAY|VARCHAR2      |JDM_STR_VALS          |  4000|        999|
|VARYING ARRAY|VARCHAR2      |KU$_DROPCOLLIST       |  4000|       1000|
|VARYING ARRAY|VARCHAR2      |KUPC$_LOBPIECES       |  4000|       4000|
|VARYING ARRAY|VARCHAR2      |ODCIRIDLIST           |  5072|      32767|
|VARYING ARRAY|VARCHAR2      |ODCIVARCHAR2LIST      |  4000|      32767|
|VARYING ARRAY|VARCHAR2      |RE$NAME_ARRAY         |    30|       1024|
|VARYING ARRAY|VARCHAR2      |RE$RULE_LIST          |    65|       1024|
|VARYING ARRAY|VARCHAR2      |SQLPROF_ATTR          |   500|       2000|
|VARYING ARRAY|VARCHAR2      |TXNAME_ARRAY          |   256|        100|
+-------------+--------------+----------------------+------+-----------+

It looks as though ORA_MINING_NUMBER_NT and ORA_MINING_VARCHAR2_NT will be the best match for my needs.

PL/SQL indexed array types

If using Oracle 12c and PL/SQL, there's also the possibility to use any of the DBMS_SQL types, which can be unnested using the TABLE(..) constructor. There are:

  • DBMS_SQL.CLOB_TABLE
  • DBMS_SQL.BINARY_FLOAT_TABLE
  • DBMS_SQL.BINARY_DOUBLE_TABLE
  • DBMS_SQL.BLOB_TABLE
  • DBMS_SQL.BFILE_TABLE
  • DBMS_SQL.DATE_TABLE
  • DBMS_SQL.NUMBER_TABLE
  • DBMS_SQL.UROWID_TABLE
  • DBMS_SQL.VARCHAR2_TABLE
  • DBMS_SQL.TIME_TABLE
  • DBMS_SQL.TIME_WITH_TIME_ZONE_TABLE
  • DBMS_SQL.TIMESTAMP_TABLE
  • DBMS_SQL.TIMESTAMP_WITH_LTZ_TABLE
  • DBMS_SQL.TIMESTAMP_WITH_TIME_ZONE_TABLE
  • DBMS_SQL.INTERVAL_DAY_TO_SECOND_TABLE
  • DBMS_SQL.INTERVAL_YEAR_TO_MONTH_TABLE
Community
  • 1
  • 1
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
2

Your question is very general - basically you can use these (VARARRAY / TABLE) without an explicit CREATE TYPE in anonymous PL/SQL blocks like this:

DECLARE
    TYPE genres IS VARRAY(4) OF book_genre.genre_name%TYPE;
    Fiction_genres genres;
    TYPE phone_no_tab IS VARRAY(6) OF VARCHAR2(20) ;
    phone_nos phone_no_tab;
BEGIN
    fiction_genres := genres('MYSTERY','SUSPENSE', 'ROMANCE','HORROR');
    phone_nos := phone_no_tab();
    phone_nos.EXTEND(2);
    phone_nos(1) := '0117 942 2508';
END;

OR like this

declare

  TYPE auftrag_table_typ IS TABLE OF auftrag%ROWTYPE
          INDEX BY BINARY_INTEGER;

  auftrag_table auftrag_table_typ;

  v_index BINARY_INTEGER;

begin

  v_index := auftrag_table.first;

  while v_index is not NULL loop

    // do something with auftrag_table(v_index)

    v_index := auftrag_table.next (v_index);

  end loop;

end; 

For Oracle reference see http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm - according to this any such VARARRAY and/or TABLE needs to be DECLAREd or created via CREATE TYPE, so AFAIK there is no such thing as "anonymous VARARRAY / TABLE".

Yahia
  • 69,653
  • 9
  • 115
  • 144
  • I can see how it can be done with PL/SQL. But when calling the statement from Java, is an anonymous PL/SQL block wrapper around the actual SQL statement really the best solution? Instead of a simple SQL statement, I'd then have to prepare a call and probably register a `REF CURSOR` parameter to return the results...? – Lukas Eder Jan 09 '12 at 08:43
  • @LukasEder your question is extremely general... and I don't know of any "best solution" in programming - it all depends on what you want to do... you asked whether these can be used without `CREATE TYPE` privilege - and that's what I answered... I don't see anything wrong with having to prepare a statement - I would even say that preparing a statement is in most cases recommended... please say what exactly you want to achieve... – Yahia Jan 09 '12 at 08:54
  • The question is quite clear. I'm looking for anonymous array types. If it doesn't exist, then the answer is simply *NO*. You're making too many assumptions about a hypothetical problem I might have :) – Lukas Eder Jan 09 '12 at 09:01
  • PL/SQL `TABLE` and `VARRAY` types cannot be used in SQL anyway (except with constructs such as `BULK COLLECT INTO`). So this is also true for SQL types? – Lukas Eder Jan 09 '12 at 09:08
  • @LukasEder what do you mean by "SQL types" ? – Yahia Jan 09 '12 at 09:13
  • According to your link they're better called *standalone stored types*, rather than *SQL types*. Please note, I'm asking this because the `COLLECT` operator creates a "temporary" type for similar purposes. Maybe there is a way to achieve what I want, using "anonymous" types – Lukas Eder Jan 09 '12 at 09:22
  • @LukasEder `COLLECT` basically does a `CREATE TYPE` in the schema of the caller - you can verify that by looking at `all_types`. – Yahia Jan 09 '12 at 09:39