web-dev-qa-db-ja.com

Oracle SQLの動的ピボット

...ピボット((X)のBの合計(A))

現在、Bはデータ型varchar2であり、Xはコンマで区切られたvarchar2値の文字列です。
Xの値は、同じテーブルの列(CLなど)から個別の値を選択します。この方法でピボットクエリは機能していました。

しかし、問題は、列CLに新しい値があるたびに、それを文字列Xに手動で追加する必要があることです。

XをCLから選択した個別の値に置き換えてみました。しかし、クエリは実行されていません。
私が感じた理由は、Xを置き換えるには値をコンマで区切る必要があるという事実によるものでした。
次に、文字列Xと一致する正確な出力を返す関数を作成しました。しかし、クエリはまだ実行されません。
表示されるエラーメッセージは、「missing righr parantheses」、「end of file communication channel」などのようなものです。

たぶん私はそれを適切に使用していません。
動的な値を持つピボットを作成する方法を教えてください。

13
prabhakar

PIVOT XMLを使用せずに、PIVOTのINステートメントに動的ステートメントを配置することはできません。PIVOTXMLは、望ましい出力よりも低い出力を出力します。ただし、IN文字列を作成してステートメントに入力することはできます。

まず、これが私のサンプルテーブルです。

  myNumber    myValue myLetter
---------- ---------- --------
         1          2 A        
         1          4 B        
         2          6 C        
         2          8 A        
         2         10 B        
         3         12 C        
         3         14 A      

まず、INステートメントで使用する文字列をセットアップします。ここでは、文字列を「str_in_statement」に入れています。 COLUMN NEW_VALUE および [〜#〜] listagg [〜#〜] を使用して文字列を設定します。

clear columns
COLUMN temp_in_statement new_value str_in_statement
SELECT DISTINCT 
    LISTAGG('''' || myLetter || ''' AS ' || myLetter,',')
        WITHIN GROUP (ORDER BY myLetter) AS temp_in_statement 
    FROM (SELECT DISTINCT myLetter FROM myTable);

文字列は次のようになります。

'A' AS A,'B' AS B,'C' AS C

ここで、PIVOTクエリでStringステートメントを使用します。

SELECT * FROM 
    (SELECT myNumber, myLetter, myValue FROM myTable)
    PIVOT (Sum(myValue) AS val FOR myLetter IN (&str_in_statement));

出力は次のとおりです。

  MYNUMBER      A_VAL      B_VAL      C_VAL
---------- ---------- ---------- ----------
         1          2          4            
         2          8         10          6 
         3         14                    12 

ただし、制限があります。連結できる文字列は最大4000バイトです。

21
user2179919

後の読者のために、ここに別のソリューションがあります https://technology.amis.nl/2006/05/24/dynamic-sql-pivoting-stealing-antons-thunder/

のようなクエリを許可する

select * from table( pivot(  'select deptno,  job, count(*) c from scott.emp group by deptno,job' ) )
4
Scott

動的クエリを使用

テストコードは以下です


--  DDL for Table TMP_TEST
--------------------------------------------------------

  CREATE TABLE "TMP_TEST" 
   (    "NAME" VARCHAR2(20), 
    "APP" VARCHAR2(20)
   );
/
SET DEFINE OFF;
Insert into TMP_TEST (NAME,APP) values ('suhaib','2');
Insert into TMP_TEST (NAME,APP) values ('suhaib','1');
Insert into TMP_TEST (NAME,APP) values ('shahzad','3');
Insert into TMP_TEST (NAME,APP) values ('shahzad','2');
Insert into TMP_TEST (NAME,APP) values ('shahzad','5');
Insert into TMP_TEST (NAME,APP) values ('tariq','1');
Insert into TMP_TEST (NAME,APP) values ('tariq','2');
Insert into TMP_TEST (NAME,APP) values ('tariq','6');
Insert into TMP_TEST (NAME,APP) values ('tariq','4');
/
  CREATE TABLE "TMP_TESTAPP" 
   (    "APP" VARCHAR2(20)
   );

SET DEFINE OFF;
Insert into TMP_TESTAPP (APP) values ('1');
Insert into TMP_TESTAPP (APP) values ('2');
Insert into TMP_TESTAPP (APP) values ('3');
Insert into TMP_TESTAPP (APP) values ('4');
Insert into TMP_TESTAPP (APP) values ('5');
Insert into TMP_TESTAPP (APP) values ('6');
/
create or replace PROCEDURE temp_test(
  pcursor out sys_refcursor,
    PRESULT                   OUT VARCHAR2
    )
AS
V_VALUES VARCHAR2(4000);
V_QUERY VARCHAR2(4000);
BEGIN
 PRESULT := 'Nothing';

-- concating activities name using comma, replace "'" with "''" because we will use it in dynamic query so "'" can effect query.
  SELECT DISTINCT 
         LISTAGG('''' || REPLACE(APP,'''','''''') || '''',',')
         WITHIN GROUP (ORDER BY APP) AS temp_in_statement 
    INTO V_VALUES
    FROM (SELECT DISTINCT APP 
            FROM TMP_TESTAPP);

-- designing dynamic query  

  V_QUERY := 'select * 
                from (  select NAME,APP 
                          from TMP_TEST   )   
               pivot (count(*) for APP in 
                     (' ||V_VALUES|| '))  
           order  by NAME' ;

    OPEN PCURSOR
     FOR V_QUERY;


 PRESULT := 'Success';

Exception
WHEN OTHERS THEN
 PRESULT := SQLcode || ' - ' || SQLERRM;
END temp_test;
2
Rana Suhaib

上記のメソッド(Anton PL/SQLカスタム関数ピボット())を使用して、仕事をしました!私はプロのOracle開発者ではないので、これらは私が行った簡単な手順です。

1)Zipパッケージをダウンロードして、pivotFun.sqlを見つけます。 2)pivotFun.sqlを一度実行して、新しい関数を作成します3)通常のSQLで関数を使用します。

動的な列名には注意してください。私の環境では、列名は30文字に制限されており、単一引用符を含めることはできません。したがって、クエリは次のようになりました。

SELECT 
  *
FROM   
  table( 
        pivot('
                SELECT DISTINCT
                    P.proj_id,
                    REPLACE(substr(T.UDF_TYPE_LABEL, 1, 30), '''''''','','') as Attribute,
                    CASE
                      WHEN V.udf_text is null     and V.udf_date is null and      V.udf_number is NOT null  THEN to_char(V.udf_number)
                      WHEN V.udf_text is null     and V.udf_date is NOT null and  V.udf_number is null      THEN to_char(V.udf_date)
                      WHEN V.udf_text is NOT null and V.udf_date is null and      V.udf_number is null      THEN V.udf_text
                      ELSE NULL END
                    AS VALUE
                FROM
                    project   P
                LEFT JOIN UDFVALUE V ON P.proj_id     = V.proj_id 
                LEFT JOIN UDFTYPE  T ON V.UDF_TYPE_ID = T.UDF_TYPE_ID
                WHERE 
                    P.delete_session_id  IS NULL AND
                    T.TABLE_NAME = ''PROJECT''
    ')
)

最大1mのレコードでうまく機能します。

1
user7144213

OPが尋ねた質問に正確に答えるつもりはありません。代わりに、動的ピボットをどのように行うことができるかを説明するだけです。

ここでは、最初に列の値を変数に取得し、動的SQL内で変数を渡すことにより、動的SQLを使用する必要があります。

[〜#〜] example [〜#〜]

下のような表があると考えてください。

enter image description here

YRの値を列名として表示し、それらの列の値をQTYから表示する必要がある場合、以下のコードを使用できます。

declare
  sqlqry clob;
  cols clob;
begin
  select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR)
  into   cols
  from   (select distinct YR from EMPLOYEE);


  sqlqry :=
  '      
  select * from
  (
      select *
      from EMPLOYEE
  )
  pivot
  (
    MIN(QTY) for YR in (' || cols  || ')
  )';

  execute immediate sqlqry;
end;
/

[〜#〜] result [〜#〜]

enter image description here

必要に応じて、一時テーブルを作成し、その一時テーブルで選択クエリを実行して結果を確認することもできます。その単純な、単にCREATE TABLE TABLENAME AS上記のコード。

sqlqry :=
'    
  CREATE TABLE TABLENAME AS
  select * from
0
Sarath Avanavu