web-dev-qa-db-ja.com

LONGをVARCHAR2にインラインでキャストする方法

背景: 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はLONG​​を取得しました

DBFiddle Demo

備考:

  • それは自己完結型のクエリでなければなりません
  • 中間オブジェクトはありません(テーブル/ビューの作成はオプションではありません)。
  • いいえPL/SQL block
  • DBMS_METADATA.GET_DDL(そうではありません)
  • WITH FUNCTION句 最後の手段として

組み込み関数をLONGからVARCHAR2にキャスト/変換/使用することはできますか?

EDIT TL; DR:

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

式に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.
7
Dr Y Wit

Oracleの専門家自身が述べたように、レガシーな理由により、SUBSTR a LONGをVARCHAR2にインライン化することはできません。 AskTomリンク

これについて その他のリンク LONGが32k LONGより短い場合は、プロシージャを使用して、さらに関数を使用してそれを行う方法が見つかります。

そして、この関数は、後でSELECTクエリで呼び出すことができます。

2
hi olaf

WITH FUNCTIONを使用して Converting 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

それを達成するためのよりエレガントな方法があるべきだと私は信じています。

2
Lukasz Szozda

Longを処理する最良の方法は次のとおりです。1)LOBタイプ(CLOBなど)を使用して一時テーブルを作成します。 2)Oracleで許可されている唯一の構文を使用します。「TO_LOBは、列long_columnのLONGまたはLONG​​ RAW値をLOB値に変換します。この関数は、LONGまたはLONG​​ RAW列、およびサブクエリの選択リストでのみ適用できます。 INSERTステートメント。」 3)一時テーブルを利用して作業を行う

0
Leon