【问题标题】:How to cast LONG to VARCHAR2 inline如何将 LONG 转换为 VARCHAR2 内联
【发布时间】:2018-04-10 00:13:01
【问题描述】:

背景:ALL_IND_EXPRESSIONS 有列

COLUMN_EXPRESSION   LONG   Function-based index expression defining the column

我知道LONG 已被弃用。我需要写类似的东西(或做其他文本操作):

SELECT 
  REPLACE(REPLACE(REPLACE(
    q'{ALTER INDEX "<index_owner>"."<index_name>" ON ... (<column_expression>)}'
   ,'<index_owner>', index_owner )
   ,'<index_name>', index_name) 
   ,'<column_expression>', column_expression) AS result
FROM all_ind_expressions;

ORA-00932:数据类型不一致:预期 NUMBER 长

DBFiddle Demo

备注:

  • 它必须是独立的查询
  • 没有中间对象(不能创建表/视图)。
  • 没有PL/SQL block
  • DBMS_METADATA.GET_DDL(不是这样的)
  • WITH FUNCTION clause 作为最后的手段

是否可以从LONG 转换/转换/使用内置函数到VARCHAR2

编辑 TL;DR:

SELECT column_expression || 'a'  -- convert to working code
FROM all_ind_expressions;

【问题讨论】:

  • @CyrilleMODIANO 提到的答案可能会有所帮助。 Converting from long to varchar2 right away using a single statement is not possible, as long has certain restrictions.官方文档有链接吗?

标签: sql oracle oracle12c


【解决方案1】:

您可以使用 XML,除非表达式包含可以阻止 XML 解析的内容。

select *
  from xmltable(
          '/ROWSET/ROW'
          passing (select dbms_xmlgen.getxmltype('select * from all_ind_expressions
                                                   where index_name = ''XDB$COMPLEX_TYPE_AK''')
                     from dual)
          columns index_owner varchar2(30) path 'INDEX_OWNER',
                  index_name varchar2(30) path 'INDEX_NAME',
                  table_owner varchar2(30) path 'TABLE_OWNER',
                  table_name varchar2(30) path 'TABLE_NAME',
                  column_expression varchar2(4000) path 'COLUMN_EXPRESSION')

INDEX_OWNER     INDEX_NAME           TABLE_OWNER     TABLE_NAME           COLUMN_EXPRESSION                  
--------------- -------------------- --------------- -------------------- -----------------------------------
XDB             XDB$COMPLEX_TYPE_AK  XDB             XDB$COMPLEX_TYPE     SYS_OP_R2O("XMLDATA"."ALL_KID")    
1 row selected.

【讨论】:

  • 感谢您的想法,我将对其进行测试 :) 我希望它适用于我的所有情况(我不想为不可解析的 XML 创建异常)
  • 我修改了这个选择以从 ALL_TAB_PARTITIONS 中提取列 HIGH_VALUE。
【解决方案2】:

正如 oracle 专家自己所说,由于遗留原因,不可能将 SUBSTR a LONG 内联到 VARCHAR2。 AskTom link.

在这个other link 上,如果 LONG 短于 32k LONG,您将找到使用过程甚至使用函数的方法。

这个函数可以稍后在 SELECT 查询中调用,这可能是您想要实现的。

【讨论】:

    【解决方案3】:

    使用WITH FUNCTIONConverting Long to Varchar2 的方法,但它仍然有点丑陋和过于复杂。

    CREATE TABLE TEST(Z INT);
    CREATE INDEX IF_DOUBLE_TEST_Z ON TEST(Z*2);
    

    查询:

    WITH FUNCTION s_convert(pindex_owner VARCHAR2, pindex_name VARCHAR2,
                            ptable_owner VARCHAR2, ptable_name VARCHAR2) 
                   RETURN VARCHAR2
    AS
      VAR1 LONG;
      VAR2 VARCHAR2(4000);
    BEGIN
      SELECT column_expression 
      INTO VAR1 
      FROM all_ind_expressions
      WHERE index_owner = pindex_owner AND index_name = pindex_name
        AND table_owner = ptable_owner AND table_name = ptable_name
        AND column_position = 1;  -- only one column indexes
    
      VAR2 := SUBSTR(VAR1, 1, 4000);
      RETURN VAR2;
    END;
    SELECT aie.*, 
      REPLACE(REPLACE(REPLACE(
         q'{ALTER INDEX "<index_owner>"."<index_name>" ON ... (<column_expression>)}'
         ,'<index_owner>', index_owner )
         ,'<index_name>', index_name) 
         ,'<column_expression>', 
           s_convert(index_owner, index_name, table_owner, table_name)) AS result
    FROM all_ind_expressions aie
    WHERE TABLE_NAME='TEST';
    

    db<>fiddle demo

    我相信应该有更优雅的方式来实现它。

    【讨论】:

      【解决方案4】:

      处理 long 的最佳方法是: 1) 创建一个 lob 类型的临时表(例如 CLOB)。 2)使用oracle唯一允许的语法: “TO_LOB 将 long_column 列中的 LONG 或 LONG RAW 值转换为 LOB 值。您只能将此函数应用于 LONG 或 LONG RAW 列,并且只能应用于 INSERT 语句中子查询的选择列表中。” 3)利用临时表来做你的事情

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-17
        • 2015-03-06
        • 2021-10-03
        • 2011-02-11
        • 1970-01-01
        • 2022-01-23
        相关资源
        最近更新 更多