【问题标题】:Anonymous TABLE or VARRAY type in OracleOracle 中的匿名 TABLE 或 VARRAY 类型
【发布时间】:2012-01-09 08:12:02
【问题描述】:

在 Oracle 中,我有时想创建诸如此类的结构

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

显然,我可以为上述声明我自己的类型。我可以在TABLEVARRAY 之间进行选择。例如:

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

在这种特殊情况下,另一种解决方案是编写类似

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

但我可能有更复杂的例子,我真的需要 TABLE / VARRAY 类型。那么,如果我的 SQL 运行在一个未知系统上,而我无法创建类型,因为我可能没有必要的授权呢?

所以我的问题是: Oracle 是否知道任何 Oracle 实例上都可用的“匿名”TABLE / VARRAY 类型?类似于 Postgres / H2 / HSQLDB 的简单ARRAY 类型?

更新:我主要从 Java 运行这个 SQL,如果这相关的话。无需向我解释 PL/SQL,我实际上只是在寻找匿名 SQL 数组类型(即“匿名”独立存储类型)。如果它们根本不存在,答案是 NO

【问题讨论】:

  • 你考虑过使用PLSQL吗?
  • @Rene: "我的 SQL 运行在一个无法创建类型的未知系统上",所以我不能使用 PL/SQL,因为我可能无法创建必要的类型/函数...除非您指的是匿名 PL/SQL 块?那么,你一般会如何解决这个问题呢?

标签: sql arrays oracle anonymous-types


【解决方案1】:

如果您不害怕显式引用 SYS 架构,则有一些。以下是我经常使用的一些(好吧odcivarchar2list 不多,因为它会占用大量内存:对于字符串我更喜欢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> 

但是,如果这些不足以满足您的需求,请运行此查询以查找更多信息:

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

当然,这个结果会因数据库而异。例如,我的数据库中的很多集合都归 XDB 所有,并不是每个系统都会安装它。我在这个答案顶部列出的四个应该在自 9iR2 (可能是早期)以来的每个数据库上都可用,尽管它们并不总是在早期版本中记录。


"请注意,ALL_COLL_TYPES 似乎是一个更好的字典视图 找到合适的类型”

这是一个很好的观点。我们还可以过滤 COLL_TYPE 以筛选出 VARRAY。该视图被引入 10g,而 ALL_TYPES 在 9i 中可用。与 Oracle 的大多数东西一样,版本越晚,它的功能就越多。

【讨论】:

  • 这是一个非常有趣的方法。不是我想的那样,但绝对聪明! :-) 请注意,ALL_COLL_TYPES 似乎是一个更好的字典视图来查找合适的类型(例如,您可以过滤 ELEM_TYPE_NAME = 'VARCHAR2'...
  • 接受的答案:缺少真正的匿名类型,我想这已经是最好的了。谢谢!
  • 我添加了一个查询及其结果here 来记录我在查询ALL_COLL_TYPES 时得到的结果...
【解决方案2】:

SQL 表和可变数组类型

用户APC here 给出了一个有趣的解决方案。对于这个问题的未来读者,看到这个查询提供了我真正感兴趣的内容可能会很有趣:

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;

导致(在 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|
+-------------+--------------+----------------------+------+-----------+

看起来ORA_MINING_NUMBER_NTORA_MINING_VARCHAR2_NT 将最适合我的需求。

PL/SQL 索引数组类型

如果使用 Oracle 12c 和 PL/SQL,还可以使用任何 DBMS_SQL 类型,可以使用 TABLE(..) 构造函数取消嵌套。有:

  • 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

【讨论】:

    【解决方案3】:

    您的问题非常笼统 - 基本上您可以在匿名 PL/SQL 块中使用这些 (VARARRAY / TABLE) 而无需显式 CREATE TYPE

    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;
    

    或者像这样

    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; 
    

    对于 Oracle 参考,请参阅 http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm - 据此,任何此类 VARARRAY 和/或 TABLE 都需要为 DECLAREd 或通过 CREATE TYPE 创建,因此 AFAIK 没有“匿名@”之类的东西987654331@/TABLE”。

    【讨论】:

    • 我可以看到它是如何使用 PL/SQL 完成的。但是,当从 Java 调用语句时,围绕实际 SQL 语句的匿名 PL/SQL 块包装器真的是最好的解决方案吗?而不是一个简单的 SQL 语句,然后我必须准备一个调用并可能注册一个 REF CURSOR 参数来返回结果......?
    • @LukasEder 你的问题非常笼统......而且我不知道编程中有任何“最佳解决方案” - 这完全取决于你想要做什么......你问这些是否可以在没有 CREATE TYPE 特权的情况下使用 - 这就是我的回答......我认为必须准备一份声明没有任何问题 - 我什至会说,在大多数情况下建议准备一份声明......请说具体是什么你想实现...
    • 这个问题很清楚。我正在寻找匿名数组类型。如果它不存在,那么答案就是NO。您对我可能遇到的假设问题做出了太多假设:)
    • PL/SQL TABLEVARRAY 类型无论如何都不能在 SQL 中使用(除了 BULK COLLECT INTO 等结构)。那么对于 SQL 类型也是如此?
    • @LukasEder 你所说的“SQL 类型”是什么意思?
    猜你喜欢
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2012-08-12
    相关资源
    最近更新 更多