【问题标题】:How can I determine string value of Oracle's datatype by its code?如何通过代码确定 Oracle 数据类型的字符串值?
【发布时间】:2025-12-26 12:05:16
【问题描述】:

我使用DBMS_SQL.DESCRIBE_COLUMNS 过程来确定我的 SELECT 查询的结果集中的列使用了哪些数据类型。但不幸的是,通过这种方式,我只能得到 Oracle 数据类型 (record.col_type) - 1、8、12 等的代码。

所以我想知道,如何轻松获得与返回数据类型代码(即 VARCHAR2、LONG、DATE 等)等效的字符串,而不是其数字代码?

【问题讨论】:

    标签: oracle plsql database


    【解决方案1】:

    这是一个稍微笨拙的解决方案,但您可以使用 CASE 语句来“查找”数据类型描述。

    case record.col_type
      when dbms_types.TYPECODE_DATE then 'DATE'             
      when dbms_types.TYPECODE_NUMBER then 'NUMBER'           
      when dbms_types.TYPECODE_RAW then 'RAW'              
      when dbms_types.TYPECODE_CHAR then 'CHAR'             
      when dbms_types.TYPECODE_VARCHAR2 then 'VARCHAR2'         
      when dbms_types.TYPECODE_VARCHAR then 'VARCHAR'          
      when dbms_types.TYPECODE_MLSLABEL then 'MLSLABEL'         
      when dbms_types.TYPECODE_BLOB then 'BLOB'             
      when dbms_types.TYPECODE_BFILE then 'BFILE'            
      when dbms_types.TYPECODE_CLOB then 'CLOB'              
      when dbms_types.TYPECODE_CFILE then 'CFILE'            
      when dbms_types.TYPECODE_TIMESTAMP then 'TIMESTAMP'        
      when dbms_types.TYPECODE_TIMESTAMP_TZ then 'TIMESTAMP_TZ'     
      when dbms_types.TYPECODE_TIMESTAMP_LTZ then 'TIMESTAMP_LTZ'    
      when dbms_types.TYPECODE_INTERVAL_YM then 'INTERVAL_YM'      
      when dbms_types.TYPECODE_INTERVAL_DS then 'INTERVAL_DS'      
      when dbms_types.TYPECODE_REF then 'REF'              
      when dbms_types.TYPECODE_OBJECT then 'OBJECT'           
      when dbms_types.TYPECODE_VARRAY then 'VARRAY'                       
      when dbms_types.TYPECODE_TABLE then 'TABLE'                        
      when dbms_types.TYPECODE_NAMEDCOLLECTION then 'NAMEDCOLLECTION'  
      when dbms_types.TYPECODE_OPAQUE then 'OPAQUE'                            
      when dbms_types.TYPECODE_NCHAR then 'NCHAR'            
      when dbms_types.TYPECODE_NVARCHAR2 then 'NVARCHAR2'       
      when dbms_types.TYPECODE_NCLOB then 'NCLOB'                  
      when dbms_types.TYPECODE_BFLOAT then 'BFLOAT'           
      when dbms_types.TYPECODE_BDOUBLE then 'BDOUBLE'          
      when dbms_types.TYPECODE_UROWID then 'UROWID'              
    end case
    

    要获取此值,您应该查询数据字典 as tbone suggests

    【讨论】:

    • 感谢您的回答,我将尝试此解决方案以及@tbone 的建议:case record.col_type when DBMS_TYPES.TYPECODE_VARCHAR then 'VARCHAR2_TYPE' when DBMS_TYPES.NUMBER then 'NUMBER_TYPE' 等等。
    • 某些整数值不在列表中,例如 TIMESTAMP 的 180 和 INTERVAL_DS 的 183。看起来有些类型有多个 id。做了一些测试后发现它。找不到任何关于它的文档。 Oracle 版本为 12.2。
    • 但是sys.col$ 为我们提供了另一组id,我们可以将它们与DBMS_TYPE 中的id 结合以获得更多类型。 select count(*) from col$; = 115462. select count(distinct type#) nvals from col$; = 24. select listagg(col_type, ', ') within group (order by col_type) col_types from (select distinct type# col_type from col$);= 1, 2, 8, 12, 23, 24, 25, 29, 58, 69, 96, 100, 101, 111, 112, 113, 121, 122、123、180、181、183、208、231。
    【解决方案2】:

    试试:

    select 
       distinct
       c.type# type_code,
       decode(c.type#, 1, decode(c.charsetform, 2, 'NVARCHAR2', 'VARCHAR2'),
                       2, decode(c.scale, null, decode(c.precision#, null, 'NUMBER', 'FLOAT'), 'NUMBER'),
                       8, 'LONG',
                       9, decode(c.charsetform, 2, 'NCHAR VARYING', 'VARCHAR'),
                       12, 'DATE',
                       23, 'RAW', 24, 'LONG RAW',
                       69, 'ROWID',
                       96, decode(c.charsetform, 2, 'NCHAR', 'CHAR'),
                       100, 'BINARY_FLOAT',
                       101, 'BINARY_DOUBLE',
                       105, 'MLSLABEL',
                       106, 'MLSLABEL',
                       111, 'REF',
                       112, decode(c.charsetform, 2, 'NCLOB', 'CLOB'),
                       113, 'BLOB', 114, 'BFILE', 115, 'CFILE',
                       121, 'USER_TYPE',
                       122, 'USER_TYPE',
                       123, 'USER_TYPE',
                       178, 'TIME(' ||c.scale|| ')',
                       179, 'TIME(' ||c.scale|| ')' || ' WITH TIME ZONE',
                       180, 'TIMESTAMP(' ||c.scale|| ')',
                       181, 'TIMESTAMP(' ||c.scale|| ')'||' WITH TIME ZONE',
                       231, 'TIMESTAMP(' ||c.scale|| ')'||' WITH LOCAL TIME ZONE',
                       182, 'INTERVAL YEAR(' ||c.precision#||') TO MONTH',
                       183, 'INTERVAL DAY(' ||c.precision#||') TO SECOND(' ||
                             c.scale || ')',
                       208, 'UROWID',
                       'UNDEFINED') type_name from sys.col$ c order by c.type#;
    

    【讨论】:

      【解决方案3】:

      使用ANYDATA.GetTypeName

      这是一个带有一些解释和示例的链接:http://www.oracle-developer.net/display.php?id=218

      我引用:

      SQL> DECLARE
        2     v_anydata  ANYDATA := ANYDATA.ConvertVarchar2('String');
        3     v_typename VARCHAR2(128);
        4  BEGIN
        5     v_typename := v_anydata.GetTypeName();
        6     DBMS_OUTPUT.PUT_LINE('Type of ANYDATA instance is [' || v_typename || ']');
        7  END;
        8  /
      
      Type of ANYDATA instance is [SYS.VARCHAR2]
      
      PL/SQL procedure successfully completed.
      

      这里是some examples of using this in a select

      【讨论】:

      • 该解决方案看起来很有趣,但请您解释一下,如何为某些 SQL 查询的每一列设置 ANYDATA 变量的类型名称? IE。我需要创建一个过程,其中 SQL 查询作为输入参数,并将该查询的每一列的字符串数据类型名称集合作为输出参数。是否可以在 ANYDATA 的帮助下实现?
      • 查看我添加的基于查询的示例的链接。
      • 感谢您提供的链接,它非常有用。我会用 ANYDATA 尝试这样的解决方案。
      【解决方案4】:

      查看 DBMS_TYPES 包(来自我的 11gr2):

      select text from all_source
      where owner='SYS'
      and name='DBMS_TYPES'
      and type='PACKAGE';
      
      PACKAGE dbms_types AS
      
        TYPECODE_DATE            PLS_INTEGER :=  12;
      
        TYPECODE_NUMBER          PLS_INTEGER :=   2;
      
        TYPECODE_RAW             PLS_INTEGER :=  95;
      
        TYPECODE_CHAR            PLS_INTEGER :=  96;
      
        TYPECODE_VARCHAR2        PLS_INTEGER :=   9;
      
        TYPECODE_VARCHAR         PLS_INTEGER :=   1;
      
        TYPECODE_MLSLABEL        PLS_INTEGER := 105;
      
        TYPECODE_BLOB            PLS_INTEGER := 113;
      
        TYPECODE_BFILE           PLS_INTEGER := 114;
      
        TYPECODE_CLOB            PLS_INTEGER := 112;
      
        TYPECODE_CFILE           PLS_INTEGER := 115;
      
        TYPECODE_TIMESTAMP       PLS_INTEGER := 187;
      
        TYPECODE_TIMESTAMP_TZ    PLS_INTEGER := 188;
      
        TYPECODE_TIMESTAMP_LTZ   PLS_INTEGER := 232;
      
        TYPECODE_INTERVAL_YM     PLS_INTEGER := 189;
      
        TYPECODE_INTERVAL_DS     PLS_INTEGER := 190;
      
      
      
        TYPECODE_REF             PLS_INTEGER := 110;
      
        TYPECODE_OBJECT          PLS_INTEGER := 108;
      
        TYPECODE_VARRAY          PLS_INTEGER := 247;            /* COLLECTION TYPE */
      
        TYPECODE_TABLE           PLS_INTEGER := 248;            /* COLLECTION TYPE */
      
        TYPECODE_NAMEDCOLLECTION PLS_INTEGER := 122;
      
        TYPECODE_OPAQUE          PLS_INTEGER := 58;                 /* OPAQUE TYPE */
      
      
      
        /* NOTE: These typecodes are for use in AnyData api only and are short forms
      
           for the corresponding char typecodes with a charset form of SQLCS_NCHAR.
      
        */
      
        TYPECODE_NCHAR           PLS_INTEGER := 286;
      
        TYPECODE_NVARCHAR2       PLS_INTEGER := 287;
      
        TYPECODE_NCLOB           PLS_INTEGER := 288;
      
      
      
        /* Typecodes for Binary Float, Binary Double and Urowid. */
      
        TYPECODE_BFLOAT          PLS_INTEGER := 100;
      
        TYPECODE_BDOUBLE         PLS_INTEGER := 101;
      
        TYPECODE_UROWID          PLS_INTEGER := 104;
      
      
      
        SUCCESS                  PLS_INTEGER := 0;
      
        NO_DATA                  PLS_INTEGER := 100;
      

      另外请注意,109 是用户定义的类型,您可能需要改用 DESCRIBE_COLUMNS3。

      【讨论】:

      • 有人可以向我解释为什么其中一些与手册中的不同吗? docs.oracle.com/cd/E11882_01/server.112/e41085/… 而且,从 SYS.DBA_TAB_COLS_V$ 视图中的内容来看,奇怪....
      • 查询获取SYS包源代码中的所有列类型代码:select regexp_substr(text, '^.*PLS_INTEGER :=\s*(\d+);.*$', 1, 1, NULL, 1) AS type_code, regexp_substr(text, '^.*TYPECODE_([^ ]+).*$', 1, 1, NULL, 1) AS type_name from all_source where owner='SYS' and name='DBMS_TYPES' and type='PACKAGE' and text like '%TYPECODE_%:=%;%' order by to_number(type_code)