記録

23203 ワード

記録は、1行の複数列のスカラーで構成され、複合データ構造である。
PL/SQLは3種類の記録タイプをサポートしています。テーブルベースの記録、ラベルベースの記録、ユーザー独自の記録です。
一、表による記録
DECLARE
   emp_rec emp%rowtype;
BEGIN
   SELECT * INTO emp_rec FROM emp WHERE empno=7788;
DBMS_OUTPUT.PUT_LINE(
'Ename is: '||emp_rec.ename); DBMS_OUTPUT.PUT_LINE('Job is: '||emp_rec.job); DBMS_OUTPUT.PUT_LINE('Salary is: '||emp_rec.sal); END;
二、ランドマークによる記録
DECLARE
  CURSOR emp_cur IS SELECT * FROM emp WHERE rownum <=4;
  emp_rec emp_cur%ROWTYPE;
BEGIN
  OPEN emp_cur;
  LOOP
     FETCH emp_cur INTO emp_rec;
     EXIT WHEN emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
'Ename is: '||emp_rec.ename); DBMS_OUTPUT.PUT_LINE('Job is: '||emp_rec.job); DBMS_OUTPUT.PUT_LINE('Salary is: '||emp_rec.sal); END LOOP; END;
三、ユーザーがカスタマイズしたレコード
ユーザー定義のレコードを作成するシンタックスは以下の通りです。
TYPE type_name IS RECORD
   (field_name1 datatype1 [NOT NULL] [ := DEFAULT EXPRESSION],
    field_name2 datatype2 [NOT NULL] [ := DEFAULT EXPRESSION],
    ...
    field_nameN datatypeN [NOT NULL] [ := DEFAULT EXPRESSION]);
record_name TYPE_NAME;
一例を挙げてみます
DECLARE
  TYPE time_rec_type IS RECORD
     (curr_date DATE,
      curr_day  VARCHAR2(12),
      curr_time VARCHAR(8) :='00:00:00'
      );   
  time_rec TIME_REC_TYPE;
BEGIN
  SELECT sysdate INTO time_rec.curr_date FROM dual;
  time_rec.curr_day := TO_CHAR(time_rec.curr_date,'DAY');
  time_rec.curr_time := TO_CHAR(time_rec.curr_date,'HH24:MI:SS');
 
DBMS_OUTPUT.PUT_LINE(
'Date: '||time_rec.curr_date); DBMS_OUTPUT.PUT_LINE('Day: '||time_rec.curr_day); DBMS_OUTPUT.PUT_LINE('Time: '||time_rec.curr_time); END;
注意:
1>記録タイプを宣言する場合、あるフィールドにNOT NULL制約を指定すると、そのフィールドを初期化しなければなりません。例えば上記の例では、フィールドがcurr_であればdateはNOT NULL制約、つまりcurr_を指定しています。date DATE NOT NULLは、エラーを報告します。PLS-00218:a variable declead NOT NULL must have an initialization assignment。初期化可能:curr_date DATE NOT NULL:=sysdate。
2> 記録は全体的に空と判断することはできません。記録フィールドだけを判断することができます。
3> 記録は全体的に比較できません。記録フィールドだけを比較することができます。
4>テーブルまたはラベルベースの記録全体をユーザーがカスタマイズした記録に割り当てることができます。両方が同じ構造を持つ限り。しかし、ユーザーがカスタマイズした記録については、2つのカスタムレコードが同じ構造を持っていても、タイプが違っていて、全体的に値を付けられません。以下の通りです
DECLARE
  TYPE name_type1 IS RECORD
     (first_name VARCHAR2(15),
      last_name  VARCHAR2(30)
      );
  TYPE name_type2 IS RECORD
     (first_name VARCHAR2(15),
      last_name  VARCHAR2(15)
      );
   name_rec1 name_type1;
   name_rec2 name_type2;
BEGIN
   name_rec1.first_name := 'John';
   name_rec1.last_name := 'Smith';
   name_rec2 := name_rec1;
END;
運転報告は以下のエラーです。
SQL>/name_rec 2:=name_rec 1;*ERROR at line 15:ORA-0650:line 15,column 17:PLS-0082:expression is of wrong typeORA-0650:line 15,column 4:PL/SQL:Sttement ignored
二つの記録は同じ構造を持っていますが、各記録の種類が違っています。この記録も互換性がなく、全体の割当値がエラーとなります。
上記の例は次のように変更できます。
DECLARE
  TYPE name_type1 IS RECORD
     (first_name VARCHAR2(15),
      last_name  VARCHAR2(30)
      );
   name_rec1 name_type1;
   name_rec2 name_type1;
BEGIN
   name_rec1.first_name := 'John';
   name_rec1.last_name := 'Smith';
   name_rec2 := name_rec1;
END;
 上記全体の割当の制限は、ユーザがカスタマイズした記録タイプに限られます。両方が同じ構造を持つ限り、テーブルまたはラベルに基づく記録全体の割当値をユーザーがカスタマイズした記録に与えることができる。
DECLARE
  CURSOR dept_cur IS SELECT * FROM dept;
  TYPE dept_type IS RECORD
     (deptno dept.deptno%TYPE,
      dname  dept.dname%TYPE,
      loc    dept.loc%TYPE
      );
   dept_rec1 dept%ROWTYPE;   -- table-based record
   dept_rec2 dept_cur%ROWTYPE; -- cursor-based record
   dept_rec3 dept_type;
BEGIN
   -- Populate table-based record
   SELECT * INTO dept_rec1 FROM dept WHERE deptno=10;
   dept_rec2 := dept_rec1; 
   dept_rec3 := dept_rec1; 
 
   --Populate cursor-based record 
   OPEN dept_cur;
   LOOP
      FETCH dept_cur INTO dept_rec2;
      EXIT WHEN dept_cur%NOTFOUND;
   END LOOP;
   dept_rec1 := dept_rec2;
   dept_rec3 := dept_rec2;
   
   --Populate user defined record
   SELECT * INTO dept_rec3 FROM dept WHERE deptno=20;
   dept_rec1 := dept_rec3;
   dept_rec2 := dept_rec3;
END;
四、ネスト記録
ネスト記録とは、他の記録とセットを含む記録のことです。
例えば:
DECLARE
  TYPE name_type IS RECORD
      (first_name  VARCHAR2(15);
       last_name   VARCHAR2(30));
  TYPE person_type IS RECORD
      (name name_type; 
       street VARCHAR2(50);
       city   VARCHAR2(25);
       state  VARCHAR2(2);
       zip    VARCHAR2(5)); 
  person_rec person_type;
                     
このコードには2つのユーザのカスタム記録タイプが含まれています。ここで、2番目のユーザがカスタム記録タイプのperson(u)typeはネストされた記録タイプで、そのフィールドnameがname_であるためです。typeタイプのレコード。
統合例:
一、部門番号を入力し、その部門の従業員を出力する
DECLARE
  TYPE ename_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
  
  TYPE dept_info_type IS RECORD
      (deptno    emp.deptno%TYPE,
       ename_tab ename_type);
  
  CURSOR name_cur (p_deptno number) IS
     SELECT ename
       FROM emp
     WHERE deptno = p_deptno;
  
  dept_info_rec dept_info_type;
  v_deptno  NUMBER(2) := &v_deptno;
  v_counter INTEGER := 0;
BEGIN
  dept_info_rec.deptno := v_deptno;
  DBMS_OUTPUT.PUT_LINE('Deptno: '||dept_info_rec.deptno||chr(10)||'Employees:');
  
  FOR name_rec IN name_cur(v_deptno) LOOP
     v_counter := v_counter+1;
     dept_info_rec.ename_tab(v_counter) := name_rec.ename;
  END LOOP;
  
  FOR i IN 1..dept_info_rec.ename_tab.COUNT LOOP
      DBMS_OUTPUT.PUT_LINE(dept_info_rec.ename_tab(i));
  END LOOP;
END;
出力結果は: 
Enter value for v_deptno:10 old 14:v_deptno NUMBER(2)=&v_deptno;new 14:v_deptno NUMBER(2):=10;Deptno:10 Employees:CLARKINGMILLER
PL/SQL procedure success fully complected.
二、各部門の従業員総数を出力する
DECLARE
  CURSOR dept_cur IS
    SELECT dname,loc,count(*) total
      FROM dept,emp
    WHERE dept.deptno=emp.deptno
    GROUP BY dname,loc;

  TYPE dname_rec_type IS RECORD
     (dname dept.dname%TYPE,
      loc   dept.loc%TYPE,
      total INTEGER);
  
  TYPE dept_type IS TABLE OF dname_rec_type INDEX BY BINARY_INTEGER;
  
  dept_tab dept_type;
  v_counter INTEGER :=0;
BEGIN
  FOR dept_rec IN dept_cur LOOP
     v_counter := v_counter+1;
     
     dept_tab(v_counter).dname := dept_rec.dname;
     dept_tab(v_counter).loc := dept_rec.loc;
     dept_tab(v_counter).total := dept_rec.total;
     
     DBMS_OUTPUT.PUT_LINE(dept_tab(v_counter).dname||' '||dept_tab(v_counter).loc
         ||' '||dept_tab(v_counter).total);
  END LOOP;
END;
出力結果は:
RESEARCH DALLAS 5 SALES CHICAGO 7 ACCOUNTING NEW YORK 3
PL/SQL procedure success fully complected.