3

column_name と value の 2 つの列を持つ結果セットに対して、常に 1 行と多数の列を持つテーブルをアンピボットするクエリを作成するにはどうすればよいですか。テーブルの根底にある構造に本当の問題があることは理解していますが、それを変更することはできません。このクエリは、列が頻繁に追加されているため、上記のテーブルの列の名前や数についての知識も持っていてはなりません (繰り返しますが、設計が悪いため、変更できません)。新しい列が追加されるたびにクエリを更新する必要があります。アンピボットを使用して近いことを達成できましたが、そのクエリでは列名をハードコーディングする必要があります。

これは可能ですか?

オラクル 11gR2

4

1 に答える 1

8

テーブルのピボットを解除したいようです (ピボットには、多数の行と 2 列から多数の列を持つ 1 行への移行が含まれます)。ほとんどの場合、動的 SQL を使用してクエリを生成し、DBMS_SQLパッケージ (または場合によってはEXECUTE IMMEDIATE) を使用して実行する必要があります。アンピボットを行ったパイプライン化されたテーブル関数を構築することもできるはずです。パイプライン化されたテーブル関数内でも動的 SQL を使用する必要がありますが、コードが少なくなる可能性があります。ただし、純粋な動的 SQL ステートメントを使用UNPIVOTすると、より効率的であることが期待されます。

非効率的なアプローチですが、比較的簡単に実行できるアプローチは、次のようなものです。

SQL> ed
Wrote file afiedt.buf

  1  create or replace type emp_unpivot_type
  2  as object (
  3    empno number,
  4    col   varchar2(4000)
  5* );
SQL> /

Type created.

SQL> create or replace type emp_unpivot_tbl
  2  as table of emp_unpivot_type;
  3  /

Type created.

SQL> ed
Wrote file afiedt.buf

  1  create or replace function unpivot_emp
  2  ( p_empno in number )
  3    return emp_unpivot_tbl
  4    pipelined
  5  is
  6    l_val varchar2(4000);
  7  begin
  8    for cols in (select column_name from user_tab_columns where table_name = 'EMP')
  9    loop
 10      execute immediate 'select ' || cols.column_name || ' from emp where empno = :empno'
 11         into l_val
 12       using p_empno;
 13      pipe row( emp_unpivot_type( p_empno, l_val ));
 14    end loop;
 15    return;
 16* end;
SQL> /

Function created.

次に、SQLステートメントでそれを呼び出すことができます(列名を持つ少なくとも3番目の列が必要だと思います)

SQL> ed
Wrote file afiedt.buf

  1  select *
  2*   from table( unpivot_emp( 7934 ))
SQL> /

     EMPNO COL
---------- ----------------------------------------
      7934 7934
      7934 MILLER
      7934 CLERK
      7934 7782
      7934 23-JAN-82
      7934 1301
      7934
      7934 10

8 rows selected.

より効率的なアプローチは、Tom Kyte のshow_table パイプライン テーブル関数を採用することです。

于 2013-02-26T22:16:59.507 に答える