2017-07-21 4 views
0

相関のない名前(ABC1、DA23、EE123 - そこに共通のパターンはありません)を持たない100列の表があります。行の列を反復する

この表のすべての行とすべての列を繰り返し処理します。

は私の現在のスクリプト:

BEGIN 
    FOR single_row IN (
     SELECT * 
     FROM MY_TABLE) 
    LOOP 
     --iterate through columns of 'single_row' 
     --for each nullable column do insert with real current column name and column value) 
     --I assume each column is nullable except of ID 
     INSERT INTO ANOTHER_TABLE VALUES (single_row.id, column_name, column_value); 
    END LOOP; 
END; 

したがって、たとえば、MY_TABLEが2行が含まれている場合:私のスクリプトを実行した後

ID|ABC1|DA23|EE123|... 
1|123|456|789|... 
2|321|654|987|... 

は、私のANOTHER_TABLEは含まれています:

MY_TABLE_ID|COLUMN_NAME|COLUMN_VALUE 
1|ABC1|123 
1|DA23|456 
1|EE123|789 
... other columns from row 1 
2|ABC1|321 
2|DA23|654 
2|EE123|987 
... other columns from row 2 

方法私がすることができます?私は、Oracle 11gのを使用してい

EDITは

@vkpは、優れたソリューションを提供しますが、解決するためのもう一つのことがあります。 in節にすべての列を指定する必要はありません。私は、それらのすべてをリストすることを強制されないように、何らかの種類のクエリを使用したり、または何か他のものを使用したいと考えています。

select * 
from MY_TABLE t 
unpivot (
    column_value for column_name in (select column_name 
     from user_tab_columns 
     where table_name = 'MY_TABLE' 
     and nullable = 'Y') 
) u 

を、それはエラーを返します:

私はこのような何かを試してみました

ORA-00904: : invalid identifier 
00904. 00000 - "%s: invalid identifier" 
+0

あなたが心配すべてが個別に各列を入力する必要がされている場合は、その理由だけで列を生成し、クエリを記述していません。ヒント:all_tab_columnsには、各テーブルの列のリストが含まれています... – Boneist

+0

@Boneist私はそれを試しましたが、エラーを返します – ilovkatie

+0

いいえ、別々にクエリを実行し、手動でピリオドをピリオドにして、unpivotクエリの関連する句に手動で貼り付けます。 – Boneist

答えて

2

これはunpivotのアプリケーションです。 IDの列のいずれかのために

select * 
from my_table m 
unpivot (column_value for column_name in (ABC1,DA23,EE123)) u 

null値が結果に表示されません。

出力にNULL値を含める必要がある場合は、オプションINCLUDE NULLSを使用します。

select * 
from my_table m 
unpivot include nulls (column_value for column_name in (ABC1,DA23,EE123)) u 

編集:

DECLARE 
sql_stmt VARCHAR2(4000); 
var_columns VARCHAR2(4000); --use clob datatype if the column names can't fit in with this datatype 

BEGIN 
SELECT LISTAGG(column_name,',') WITHIN GROUP(ORDER BY column_name) 
INTO var_columns 
FROM user_tab_columns 
WHERE table_name='MY_TABLE' AND column_name<>'ID'; 

sql_stmt:='select * from my_table m 
      unpivot 
      (column_value for column_name in (' || var_columns || ')) u'; 

EXECUTE IMMEDIATE sql_stmt; 
END; 
/
+0

素晴らしい解決策ですが、不完全です。あなたの解決策では、 '(ABC1、DA23、EE123)'の列の名前を指定する必要があります。私は100の列を持っていて、それ以上のことができるので、そこにすべての列を書きたいとは思わない。どうすればこの問題を解決できますか? – ilovkatie

+0

@ilovkatie ..編集をチェックしてください。 –

0

最初のオプションを使用して、動的に列名を含めます。動的SQLを使用します。

declare 
     v_ctx number; 
     v_query varchar2(500); 
     v_total NUMBER;   
     v_desctab DBMS_SQL.DESC_TAB; 
     v_column_cnt  NUMBER;  
     v_value varchar2(32767); 
     v_result clob := ''; 
     v_rownum number := 0; 
    begin 
     v_ctx := dbms_sql.open_cursor; 
     v_query := 'select * from user_objects where rownum < 100'; 
     dbms_sql.parse(v_ctx,v_query,dbms_sql.v7);  
     v_total := dbms_sql.execute(v_ctx); 
     DBMS_SQL.DESCRIBE_COLUMNS(v_ctx, v_column_cnt, v_desctab); 
     for i in 1 .. v_column_cnt loop 
      dbms_sql.define_column(v_ctx, i, v_value /* data_type varchar2*/, 32767 /* max_length*/); 
     end loop;     
    loop 
     exit when dbms_sql.fetch_rows(v_ctx) = 0; 
     v_rownum := v_rownum +1; 
     for i in 1 .. v_column_cnt loop   
      dbms_sql.column_value(v_ctx, i, v_value); 
      dbms_output.put_line(v_rownum||' - '||v_desctab(i).col_name||' - '||v_value); 
     end loop;   
    end loop; 
    dbms_sql.close_cursor(v_ctx); 
    exception 
     when others then 
       dbms_sql.close_cursor(v_ctx); 
        raise; 

    end; 
/

xqueryの2番目のオプション。

select t1.id,t2.* from xmltable('for $i in ora:view("<you_table_here>")/ROW 
      return $i' 
      columns id FOR ORDINALITY 
      , row_value xmltype path'.'   
      ) t1 
      ,xmltable('for $i in $row_value/ROW/* return $i' 
       passing t1.row_value as "row_value" 
       columns col_index for ORDINALITY , 
        column_name varchar2(100) path 'name()', 
        column_value varchar2(100) path 'text()' 
      ) t2 
+0

私は2番目の解決策をもっと多く、次に1番目を楽しむ。結果はもう一度、ほぼ正しいです。入力テーブルから1つの列を除外したい。私の例が示すように、入力テーブルには結果テーブルから除外されたIDカラムが含まれています – ilovkatie

+0

私は第1の解決策が醜く見えるが、より良いことを知っています。除外したい場合は、2番目のxmltableにwhere句を追加し、 'xquery flower'について何かを見つけてください。 $ row_value/ROW/*内の$ iに対して "$ i"または他の方法で$を返す$ row_value/ROW/*内の$ i/name()ne ""の$ iに対して、 ' "return to $ i' –

0

ここでは、REF CURSORを使用した簡単な解決法を示します。

私はこのコードを試してみましたが、それは私の最後で働いています。

DECLARE 
query_2 VARCHAR2(1000); 
TYPE icur IS REF CURSOR; 
ic icur; 
col_val VARCHAR2(100); 
BEGIN 
    FOR j IN 
    (SELECT * FROM user_tab_cols WHERE table_name = UPPER('MY_TABLE')) 
LOOP 
    dbms_output.put_line(j.column_name); 
    query_2 := 'SELECT ' || j.column_name|| ' FROM MY_TABLE'; 
OPEN ic FOR query_2; 
LOOP 
    FETCH ic INTO col_val; 
    EXIT WHEN ic%NOTFOUND; 
    INSERT INTO ANOTHER_TABLE VALUES(j.column_name, col_val); 
END LOOP; 

END LOOP; END; /

+0

@ilovkatieはこの解決策を試しましたか?それはあなたのために働くのですか? – ihm017

関連する問題