sql >> データベース >  >> RDS >> Oracle

OracleEXPAND_SQL_TEXTの使用

    データベーステーブルは静的エンティティではありません。通常の挿入/更新/削除イベントに加えて、時折DDLを実行して、列を追加したり、列を削除したり、必要な制約やインデックスを追加したりできます。最初の2つの項目は、明示的な変数が使用されている場合に処理する必要のある列の数を変更することにより、ストアドプロシージャ、パッケージ、関数、および場合によってはトリガーに問題を引き起こす可能性があります。プログラマーがレコード変数を使用した場合(以下に示すように)、問題が発生する可能性はほとんどありません。

    SPLEEBO @ gwankus > 
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Code to display all employee information
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- This should succeed
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > declare
      2  	     cursor get_emp_info is
      3  	     select * From emp;
      4  begin
      5  	     for emp_rec in get_emp_info loop
      6  		     dbms_output.put_line(emp_rec.empno||' '||emp_rec.ename||' '||emp_rec.job||' '||emp_rec.mgr||' '||emp_rec.hiredate||' '||emp_rec.sal||' '||emp_rec.comm||' '||emp_rec.deptno);
      7  	     end loop;
      8  end;
      9  /
    7369 SMITH CLERK 7902 17-DEC-80 800  20                                         
    7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30                                  
    7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30                                   
    7566 JONES MANAGER 7839 02-APR-81 2975  20                                      
    7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30                                
    7698 BLAKE MANAGER 7839 01-MAY-81 2850  30                                      
    7782 CLARK MANAGER 7839 09-JUN-81 2450  10                                      
    7788 SPLEEBO ANALYST 7566 09-DEC-82 3000  20                                      
    7839 KING PRESIDENT  17-NOV-81 5000  10                                         
    7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30                                   
    ...
    6100 MILLER CLERK 7782 23-SEP-97 1300  10                                       
    SPLEEBO @ gwankus > 
    

    明示的な変数が使用されている場合、変更が原因でコードが失敗する可能性があります。エラーメッセージに次のメッセージが表示されると、戸惑う可能性があります。

    PLS-00394: wrong number of values in the INTO list of a FETCH statement 
    

    もちろん、調査により、失敗の前に「alter table…」ステートメントが実行されたことが明らかになるか、影響を受けるテーブルのdescribeが、コードが最初に記述されたときとは異なる数の列を報告します。この事実がわかったら、問題の修正はそれを書いた開発者次第です。そのような変更を行う方法については、選択肢があります。

    明示的にコード化された変数と追加された列を使用した例を見て、DBMS_UTILITYパッケージのプロシージャEXPAND_SQL_TEXTを使用して、変更されたテーブルから完全な列リストを生成し、コード変更の参照として使用する方法を見てみましょう。まず、元のコードとそれが生成するエラー:

    SPLEEBO @ gwankus > 
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Code to display all employee information
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Fails because not enough variables are declared
    SPLEEBO @ gwankus > -- and populated
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > declare
      2  	     v_empno emp.empno%type;
      3  	     v_ename emp.ename%type;
      4  	     v_job   emp.job%type;
      5  	     v_mgr   emp.mgr%type;
      6  	     v_hiredate      emp.hiredate%type;
      7  	     v_sal   emp.sal%type;
      8  	     v_comm  emp.comm%type;
      9  	     v_deptno	     emp.deptno%type;
     10  
     11  	     cursor get_emp_info is
     12  	     select * From emp;
     13  begin
     14  	     open get_emp_info;
     15  	     loop
     16  		     fetch get_emp_info into v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno;
     17  		     exit when get_emp_info%notfound;
     18  		     dbms_output.put_line(v_empno||' '||v_ename||' '||v_job||' '||v_mgr||' '||v_hiredate||'  '||v_sal||' '||v_comm||' '||v_deptno);
     19  	     end loop;
     20  end;
     21  /
    		fetch get_emp_info into v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno;
    		*
    ERROR at line 16:
    ORA-06550: line 16, column 3: 
    PLS-00394: wrong number of values in the INTO list of a FETCH statement 
    ORA-06550: line 16, column 3: 
    PL/SQL: SQL Statement ignored 
    
    
    SPLEEBO @ gwankus > 
    SPLEEBO @ gwankus > 
    

    元のコードのコピーを作成し(必要に応じて保持するため)、DBMS_UTILITY.EXPAND_SQL_TEXTを使用して、変更されたテーブルに対する「select*from…」クエリの拡張結果をコメントとして生成します。プロシージャでは、プロシージャ呼び出しの結果を保持するためにCLOB変数を宣言する必要があります。また、操作するには特定の「select*」クエリが必要です。以下に示すコードは、この出力をコメントとして生成し、提供されたクエリでテーブル名を編集することで再利用できます。

    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus >-- Expand the 'select *' query to see all
    SPLEEBO @ gwankus >-- of the returned columns
    SPLEEBO @ gwankus >--
    SPLEEBO @ gwankus >-- Add the output to the failing script
    SPLEEBO @ gwankus >-- to facilitate corrective edits
    SPLEEBO @ gwankus >--
    SPLEEBO @ gwankus >spool new_query.sql
    SPLEEBO @ gwankus >declare
      2    l_clob clob;
      3  begin
      4    dbms_utility.expand_sql_text (
      5      input_sql_text  => 'select * from emp',
      6      output_sql_text => l_clob
      7    );
      8
      9    dbms_output.put_line('/*');
     10    dbms_output.put_line(lower(l_clob));
     11    dbms_output.put_line('*/');
     12  end;
     13  /
    
    /*                                                                              
    select "a1"."empno" "empno","a1"."ename" "ename","a1"."job" "job","a1"."mgr"    
    "mgr","a1"."hiredate" "hiredate","a1"."sal" "sal","a1"."comm"                   
    "comm","a1"."deptno" "deptno","a1"."term_dt" "term_dt" from "scott"."emp" "a1"  
    */                                                                              
    
    PL/SQL procedure successfully completed.
    
    SPLEEBO @ gwankus > spool off
    

    作業コピーを作成し、上記のクエリの出力をそれに追加します。次に、選択したエディターで変更したファイルを開いて、必要な変更を加えます。

    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Copy the original script to preserve code
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > !cp emp_info_pl_orig.sql emp_info_pl.sql
    
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Add the output generated above as a comment
    SPLEEBO @ gwankus > -- for reference purposes
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > !cat new_query.sql >> emp_info_pl.sql
    
    SPLEEBO @ gwankus > 
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Edit the script copy to fix the issue by
    SPLEEBO @ gwankus > -- adding the necessary variable declaration
    SPLEEBO @ gwankus > -- and editing the code to populate it
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > !vi emp_info_pl.sql
    
    declare
            v_empno emp.empno%type;
            v_ename emp.ename%type;
            v_job   emp.job%type;
            v_mgr   emp.mgr%type;
            v_hiredate      emp.hiredate%type;
            v_sal   emp.sal%type;
            v_comm  emp.comm%type;
            v_deptno        emp.deptno%type;
            v_term_dt        emp.term_dt%type;
    
            cursor get_emp_info is
            select * From emp;
    begin
            open get_emp_info;
            loop
                    fetch get_emp_info into v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno, v_term_dt;
                    exit when get_emp_info%notfound;
                    dbms_output.put_line(v_empno||' '||v_ename||' '||v_job||' '||v_mgr||' '||v_hiredate||' '||v_sal||' 
    '||v_comm||' '||v_deptno||' '||v_term_dt); end loop; end; / /* select "a1"."empno" "empno","a1"."ename" "ename","a1"."job" "job","a1"."mgr" "mgr","a1"."hiredate" "hiredate","a1"."sal" "sal","a1"."comm" "comm","a1"."deptno" "deptno","a1"."term_dt" "term_dt" from "scott"."emp" "a1" */

    変更をテストして、すべてが期待どおりに機能することを確認します。

    SPLEEBO @ gwankus > 
    SPLEEBO @ gwankus > set head on feedback on pagesize 60
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Run modified code
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- The anonymous block now completes
    SPLEEBO @ gwankus > -- without error
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > @emp_info_pl
    SPLEEBO @ gwankus > declare
      2  	     v_empno emp.empno%type;
      3  	     v_ename emp.ename%type;
      4  	     v_job   emp.job%type;
      5  	     v_mgr   emp.mgr%type;
      6  	     v_hiredate      emp.hiredate%type;
      7  	     v_sal   emp.sal%type;
      8  	     v_comm  emp.comm%type;
      9  	     v_deptno	     emp.deptno%type;
     10  	     v_term_dt	      emp.term_dt%type;
     11  
     12  	     cursor get_emp_info is
     13  	     select * From emp;
     14  begin
     15  	     open get_emp_info;
     16  	     loop
     17  		     fetch get_emp_info into v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno, v_term_dt;
     18  		     exit when get_emp_info%notfound;
     19  		     dbms_output.put_line(v_empno||' '||v_ename||' '||v_job||' '||v_mgr||' '||v_hiredate||' '||v_sal||' '||v_comm||' '||v_deptno||' '||v_term_dt);
     20  	     end loop;
     21  end;
     22  /
    7369 SMITH CLERK 7902 17-DEC-80 800  20 31-DEC-99                               
    7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 31-DEC-99                        
    7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 31-DEC-99                         
    7566 JONES MANAGER 7839 02-APR-81 2975  20 31-DEC-99                            
    7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 31-DEC-99                      
    7698 BLAKE MANAGER 7839 01-MAY-81 2850  30 31-DEC-99                            
    7782 CLARK MANAGER 7839 09-JUN-81 2450  10 31-DEC-99                            
    7788 SPLEEBO ANALYST 7566 09-DEC-82 3000  20 31-DEC-99                            
    7839 KING PRESIDENT  17-NOV-81 5000  10 31-DEC-99                               
    ...
    6100 MILLER CLERK 7782 23-SEP-97 1300  10 31-DEC-99                             
    
    PL/SQL procedure successfully completed.
    
    SPLEEBO @ gwankus > --
    

    これと同じ手法を、比較的多数の列を持つテーブルで使用できます。

    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Let's take another example
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > -- Create a table with 21 columns
    SPLEEBO @ gwankus > -- and populate it
    SPLEEBO @ gwankus > --
    SPLEEBO @ gwankus > @lotsa_cols
    SPLEEBO @ gwankus > create table lotsacols(
      2  a1      number,
      3  a2      number,
      4  a3      number,
      5  a4      number,
      6  a5      number,
      7  a6      number,
      8  a7      number,
      9  a8      number,
     10  a9      number,
     11  a10     number,
     12  a11     number,
     13  a12     number,
     14  a13     number,
     15  a14     number,
     16  a15     number,
     17  a16     number,
     18  a17     number,
     19  a18     number,
     20  a19     number,
     21  a20     number,
     22  a21     number);
    
    Table created.
    
    SPLEEBO @ gwankus > 
    SPLEEBO @ gwankus > begin
      2  	     for z in 1..1000 loop
      3  		     insert into lotsacols(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21)
      4  		     values(mod(z,3)+1,mod(z,13)+1,mod(z,21)+1,mod(z,34)+1,mod(z,47)+1,mod(z,53)+1,
    mod(z,67)+1,mod(z,79)+1,mod(z,81)+1,mod(z,97)+1,mod(z,3)+1,mod(z,7)+1,mod(z,6)+1,mod(z,2)+1,
    mod(z,9)+1,mod(z,8)+1,mod(z,101)+1,mod(z,407)+1,mod(z,313)+1,mod(z,271)+1,mod(z,133)+1); 5 end loop; 6 7 commit; 8 end; 9 / PL/SQL procedure successfully completed. SPLEEBO @ gwankus > SPLEEBO @ gwankus > SPLEEBO @ gwankus > -- SPLEEBO @ gwankus > -- Rather than do a DESC on the table SPLEEBO @ gwankus > -- use expand_sql_text to generate the SPLEEBO @ gwankus > -- column list and spool it to a file for SPLEEBO @ gwankus > -- later use SPLEEBO @ gwankus > -- SPLEEBO @ gwankus > -- Edit that file to create a working block SPLEEBO @ gwankus > -- of PL/SQL to generate results from the SPLEEBO @ gwankus > -- table data SPLEEBO @ gwankus > -- /* select "a1"."a1" "a1","a1"."a2" "a2","a1"."a3" "a3","a1"."a4" "a4","a1"."a5" "a5","a1"."a6" "a6","a1"."a7" "a7","a1"."a8" "a8","a1"."a9" "a9","a1"."a10" "a10","a1"."a11" "a11","a1"."a12" "a12","a1"."a13" "a13","a1"."a14" "a14","a1"."a15" "a15","a1"."a16" "a16","a1"."a17" "a17","a1"."a18" "a18","a1"."a19" "a19","a1"."a20" "a20","a1"."a21" "a21" from "scott"."lotsacols" "a1" */ declare cursor get_lotsa is select * From lotsacols; begin dbms_output.put_line('Your lucky LOTTO numbers are: '); for lotsa in get_lotsa loop dbms_output.put_line(lotsa.a1||' '||lotsa.a6||' '||lotsa.a7||' '||lotsa.a13||' '||lotsa.a17||' '||lotsa.a20); end loop; end; / SPLEEBO @ gwankus > -- SPLEEBO @ gwankus > -- Execute the code SPLEEBO @ gwankus > -- Your lucky LOTTO numbers are: 2 50 8 5 7 209 3 51 9 6 8 210 1 52 10 1 9 211 ... 2 53 11 2 10 212 1 32 51 1 14 179 2 33 52 2 15 180 3 34 53 3 16 181 PL/SQL procedure successfully completed.

    EXPAND_SQL_TEXTを使用すると、DESCを使用してテーブルリストを生成し、結果をスプールするよりも簡単になります。これにより、変更手順に簡単に組み込むことができる小さなファイルが作成されます。展開されたSQLテキストはコメントとして生成されるため、さらにコードを変更する必要がある場合や必要な場合に備えて、編集が完了した後もそのままにしておくことができます。

    選択は開発者が行うことですが、コード編集を容易にするために、Oracleにある程度自動化された方法で使用可能な出力を生成させる方が確かに簡単なようです。結局のところ、最も重要なのは開発者が快適なものです。ただし、EXPAND_SQL_TEXTを使用して、編集中のスクリプトにその参照情報を配置し、コードの2つの画面間で迷子にならないようにすることを検討する価値があるかもしれません。編集時間を節約できます。

    ###

    David Fitzjarrellの記事を見る


    1. T-SQLを使用してSQLServerで計算列の定義を取得する方法

    2. Oracleで数値をフォーマットする方法

    3. PostgreSQLとは何ですか?

    4. MySQLとMariaDBでテーブルを一覧表示する方法