レコード変数
次のいずれかの方法でレコード変数を作成できます。
-
RECORD
型を定義し、次にその型の変数を宣言します。 -
データベースの表またはビュー内の行の全体または一部を表すレコード変数を宣言するには、
%ROWTYPE
を使用します。 -
事前に宣言されているレコード変数と同じ型のレコード変数を宣言するには、
%TYPE
を使用します。
(構文およびセマンティクスの詳細は、「レコード変数の宣言」を参照してください。)
ここでのトピック
レコード変数の初期値
RECORD
型のレコード変数の場合、型を定義するときに別の初期値を指定しないかぎり、各フィールドの初期値はNULL
になります。
%ROWTYPE
または%TYPE
を使用して宣言したレコード変数の場合、各フィールドの初期値はNULL
になります。この変数は、参照先項目の初期値を継承しません。
レコード定数の宣言
レコード定数を宣言する場合、修飾式の位置表記法または名前関連付け表記法を使用して、値を簡潔な形式で初期化できます。
例6-39 レコード定数の宣言
この例は、修飾式を使用して初期化されるレコード定数rを示しています。0と1の値は、位置表記法を使用して指定されたMy_Rec型マークと集計を明示的に示すことによって割り当てられます。
Live SQL:
この例は、Oracle Live SQLの「レコード定数の宣言」で表示および実行できます
DECLARE
TYPE My_Rec IS RECORD (a NUMBER, b NUMBER);
r CONSTANT My_Rec := My_Rec(0,1);
BEGIN
DBMS_OUTPUT.PUT_LINE('r.a = ' || r.a);
DBMS_OUTPUT.PUT_LINE('r.b = ' || r.b);
END;
/
Oracle Databaseリリース18cより前では、同じ結果を得るために、初期値をレコードに移入するファンクションを使用してレコード定数を宣言し、定数宣言でファンクションを起動する必要がありました。両方の例を比較すると、修飾式によってよりコンパクトにできることで、プログラムの明確性と開発者の生産性が向上することがわかります。
CREATE OR REPLACE PACKAGE My_Types AUTHID CURRENT_USER IS
TYPE My_Rec IS RECORD (a NUMBER, b NUMBER);
FUNCTION Init_My_Rec RETURN My_Rec;
END My_Types;
/
CREATE OR REPLACE PACKAGE BODY My_Types IS
FUNCTION Init_My_Rec RETURN My_Rec IS
Rec My_Rec;
BEGIN
Rec.a := 0;
Rec.b := 1;
RETURN Rec;
END Init_My_Rec;
END My_Types;
/
DECLARE
r CONSTANT My_Types.My_Rec := My_Types.Init_My_Rec();
BEGIN
DBMS_OUTPUT.PUT_LINE('r.a = ' || r.a);
DBMS_OUTPUT.PUT_LINE('r.b = ' || r.b);
END;
/
結果:
r.a = 0 r.b = 1
例6-40 レコード定数の宣言
この例は、位置表記法を使用して修飾式で初期化されたレコード定数c_smallを示しています。c_largeレコード定数は、名前関連付け表記法を使用して修飾式で初期化されます。
DECLARE
TYPE t_size IS RECORD (x NUMBER, y NUMBER);
c_small CONSTANT t_size := t_size(32,36);
c_large CONSTANT t_size := t_size(x => 192, y => 292);
BEGIN
DBMS_OUTPUT.PUT_LINE('Small size is ' || c_small.x || ' by ' || c_small.y);
DBMS_OUTPUT.PUT_LINE('Large size is ' || c_large.x || ' by ' || c_large.y);
END;
/
結果:
Small size is 32 by 36 Large size is 192 by 292
RECORD型
PL/SQLブロック内に定義されるRECORD
型はローカル型です。ブロック内でのみ使用可能であり、スタンドアロン・サブプログラムまたはパッケージ・サブプログラム内にブロックがある場合にのみ、データベースに格納されます。
パッケージ仕様部に定義されるRECORD
型はパブリック項目です。パッケージ名(package_name.type_name
)で修飾することで、パッケージの外から参照できます。パブリック項目は、DROP
PACKAGE
文を使用してパッケージを削除するまで、データベースに格納されます。
スキーマ・レベルではRECORD
型を宣言できません。したがって、RECORD
型はADT属性のデータ型にできません。
RECORD
型を定義するには、型の名前とフィールドを指定します。フィールドを定義するには、フィールド名とデータ型を指定します。デフォルトでは、フィールドの初期値はNULL
です。フィールドにNOT
NULL
制約を指定できますが、指定する場合は、初期値にNULL
以外の値を指定する必要があります。NOT
NULL
制約がない場合、NULL
以外の初期値はオプションです。
パッケージ仕様部で定義されたRECORD型は、同一定義のローカル
RECORD
型と互換性がありません。
例6-41 RECORD型の定義および変数の宣言
この例では、DeptRecTyp
という名前のRECORD
型を定義し、各フィールドに初期値を指定します。その後、dept_rec
という名前でその型の変数を宣言し、変数のフィールドを出力します。
Live SQL:
この例は、Oracle Live SQLの「RECORD型の定義および変数の宣言」で表示および実行できます
DECLARE TYPE DeptRecTyp IS RECORD ( dept_id NUMBER(4) NOT NULL := 10, dept_name VARCHAR2(30) NOT NULL := 'Administration', mgr_id NUMBER(6) := 200, loc_id NUMBER(4) := 1700 ); dept_rec DeptRecTyp; BEGIN DBMS_OUTPUT.PUT_LINE('dept_id: ' || dept_rec.dept_id); DBMS_OUTPUT.PUT_LINE('dept_name: ' || dept_rec.dept_name); DBMS_OUTPUT.PUT_LINE('mgr_id: ' || dept_rec.mgr_id); DBMS_OUTPUT.PUT_LINE('loc_id: ' || dept_rec.loc_id); END; /
結果:
dept_id: 10 dept_name: Administration mgr_id: 200 loc_id: 1700
例6-42 RECORDフィールドを持つRECORD型(ネストされたレコード)
この例では、name_rec
およびcontact
という2つのRECORD
型を定義します。型contact
には型name_rec
のフィールドを含めます。
Live SQL:
この例は、Oracle Live SQLの「RECORDフィールドを持つRECORD型(ネストされたレコード)」で表示および実行できます
DECLARE TYPE name_rec IS RECORD ( first employees.first_name%TYPE, last employees.last_name%TYPE ); TYPE contact IS RECORD ( name name_rec, -- nested record phone employees.phone_number%TYPE ); friend contact; BEGIN friend.name.first := 'John'; friend.name.last := 'Smith'; friend.phone := '1-650-555-1234'; DBMS_OUTPUT.PUT_LINE ( friend.name.first || ' ' || friend.name.last || ', ' || friend.phone ); END; /
結果:
John Smith, 1-650-555-1234
例6-43 VARRAYフィールド持つRECORD型
この例では、full_name
というVARRAY
型と、contact
というRECORD
型を定義します。型contact
には型full_name
のフィールドを含めます。
Live SQL:
この例は、Oracle Live SQLの「VARRAYフィールド持つRECORD型」で表示および実行できます
DECLARE TYPE full_name IS VARRAY(2) OF VARCHAR2(20); TYPE contact IS RECORD ( name full_name := full_name('John', 'Smith'), -- varray field phone employees.phone_number%TYPE ); friend contact; BEGIN friend.phone := '1-650-555-1234'; DBMS_OUTPUT.PUT_LINE ( friend.name(1) || ' ' || friend.name(2) || ', ' || friend.phone ); END; /
結果:
John Smith, 1-650-555-1234
例6-44 同一定義のパッケージRECORD型とローカルRECORD型
この例では、パッケージpkg
と無名ブロックで、同じRECORD
型rec_type
を定義します。パッケージでは、rec_type
のパラメータを取るプロシージャprint_rec_type
を定義します。無名ブロックでは、パッケージ型(pkg.rec_type
)の変数r1
と、ローカル型(rec_type
)の変数r2
を宣言します。無名ブロックは、r1
をprint_rec_type
に渡せますが、r2
をprint_rec_type
に渡すことはできません。
Live SQL:
この例は、Oracle Live SQLの「同一定義のパッケージRECORD型とローカルRECORD型」で表示および実行できます
CREATE OR REPLACE PACKAGE pkg AS TYPE rec_type IS RECORD ( -- package RECORD type f1 INTEGER, f2 VARCHAR2(4) ); PROCEDURE print_rec_type (rec rec_type); END pkg; / CREATE OR REPLACE PACKAGE BODY pkg AS PROCEDURE print_rec_type (rec rec_type) IS BEGIN DBMS_OUTPUT.PUT_LINE(rec.f1); DBMS_OUTPUT.PUT_LINE(rec.f2); END; END pkg; / DECLARE TYPE rec_type IS RECORD ( -- local RECORD type f1 INTEGER, f2 VARCHAR2(4) ); r1 pkg.rec_type; -- package type r2 rec_type; -- local type BEGIN r1.f1 := 10; r1.f2 := 'abcd'; r2.f1 := 25; r2.f2 := 'wxyz'; pkg.print_rec_type(r1); -- succeeds pkg.print_rec_type(r2); -- fails END; /
結果:
pkg.print_rec_type(r2); -- fails * ERROR at line 14: ORA-06550: line 14, column 3: PLS-00306: wrong number or types of arguments in call to 'PRINT_REC_TYPE'
%ROWTYPE属性を使用した項目の宣言
%ROWTYPE
属性を使用すると、データベースの表またはビュー内の行の全体または一部を表すレコード変数を宣言できます。
構文およびセマンティクスの詳細は、「%ROWTYPE属性」を参照してください。
ここでのトピック
常に行の全体を表すレコード変数の宣言
常にデータベースの表またはビュー内の行の全体を表すレコード変数を宣言するには、次の構文を使用します。
variable_name table_or_view_name%ROWTYPE;
このレコードは、表またはビューのすべての列に対して、同じ名前とデータ型のフィールドを持ちます。
関連項目:
%ROWTYPE
の詳細は、「%ROWTYPE属性」を参照してください
例6-45 データベース表の行全体を表す%ROWTYPE変数
この例では、表departments
の行を表すレコード変数を宣言し、フィールドに値を代入してからフィールドを出力します。この例を例6-41と比較してください。
Live SQL:
この例は、Oracle Live SQLの「データベース表の行全体を表す%ROWTYPE変数」で表示および実行できます
DECLARE
dept_rec departments%ROWTYPE;
BEGIN
-- Assign values to fields:
dept_rec.department_id := 10;
dept_rec.department_name := 'Administration';
dept_rec.manager_id := 200;
dept_rec.location_id := 1700;
-- Print fields:
DBMS_OUTPUT.PUT_LINE('dept_id: ' || dept_rec.department_id);
DBMS_OUTPUT.PUT_LINE('dept_name: ' || dept_rec.department_name);
DBMS_OUTPUT.PUT_LINE('mgr_id: ' || dept_rec.manager_id);
DBMS_OUTPUT.PUT_LINE('loc_id: ' || dept_rec.location_id);
END;
/
結果:
dept_id: 10
dept_name: Administration
mgr_id: 200
loc_id: 1700
例6-46 初期値または制約を継承しない%ROWTYPE変数
この例では、2つの列を持つ表を作成し、それぞれの列に初期値とNOT
NULL
制約を指定します。次に、この表の行を表すレコード変数を宣言してからフィールドを出力し、初期値またはNOT
NULL
制約が変数に継承されなかったことを示します。
Live SQL:
この例は、Oracle Live SQLの「初期値または制約を継承しない%ROWTYPE変数」で表示および実行できます
CREATE OR REPLACE PROCEDURE print (n INTEGER) IS
BEGIN
IF n IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE(n);
ELSE
DBMS_OUTPUT.PUT_LINE('NULL');
END IF;
END print;
/
DROP TABLE t1;
CREATE TABLE t1 (
c1 INTEGER DEFAULT 0 NOT NULL,
c2 INTEGER DEFAULT 1 NOT NULL
);
DECLARE
t1_row t1%ROWTYPE;
BEGIN
DBMS_OUTPUT.PUT('t1.c1 = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(t1_row.c1), 'NULL'));
DBMS_OUTPUT.PUT('t1.c2 = '); print(t1_row.c2);
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(t1_row.c2), 'NULL'));
END;
/
結果:
t1.c1 = NULL
t1.c2 = NULL
行の一部を表すことができるレコード変数の宣言
データベースの表またはビュー内の行の一部を表すことができるレコード変数を宣言するには、次の構文を使用します。
variable_name cursor%ROWTYPE;
カーソルは問合せに関連付けられています。問合せにより選択されるすべての列に対して、レコード変数の中には、対応する型互換のフィールドが存在している必要があります。問合せにより表またはビュー内のすべての列が選択される場合、変数は行の全体を表しますが、それ以外の場合は、行の一部を表します。カーソルは、明示カーソルまたは強いカーソル変数のいずれかである必要があります。
関連項目:
-
構文の詳細は、「FETCH文」を参照してください
-
カーソルの詳細は、「カーソルの概要」を参照してください
-
明示カーソルの詳細は、「明示カーソル」を参照してください
-
カーソル変数の詳細は、「カーソル変数」を参照してください
-
結合の詳細は、『Oracle Database SQL言語リファレンス』を参照してください
例6-47 データベース表の行の一部を表す%ROWTYPE変数
この例では、サンプル・スキーマHR
のemployees
表から列first_name
、last_name
およびphone_number
のみを選択する問合せが指定された明示カーソルを宣言します。次に、カーソルにより選択される各列に対応するフィールドを持つレコード変数を宣言します。この変数はemployees
の行の一部を表します。この例を例6-42と比較してください。
Live SQL:
この例は、Oracle Live SQLの「データベース表の行の一部を表す%ROWTYPE変数」で表示および実行できます
DECLARE
CURSOR c IS
SELECT first_name, last_name, phone_number
FROM employees;
friend c%ROWTYPE;
BEGIN
friend.first_name := 'John';
friend.last_name := 'Smith';
friend.phone_number := '1-650-555-1234';
DBMS_OUTPUT.PUT_LINE (
friend.first_name || ' ' ||
friend.last_name || ', ' ||
friend.phone_number
);
END;
/
結果:
John Smith, 1-650-555-1234
例6-48 結合行を表す%ROWTYPE変数
この例では、結合問合せが指定された明示カーソルを定義した後、このカーソルにより選択される各列に対応するフィールドを持つレコード変数を宣言します。
Live SQL:
この例は、Oracle Live SQLの「結合行を表す%ROWTYPE変数」で表示および実行できます
DECLARE
CURSOR c2 IS
SELECT employee_id, email, employees.manager_id, location_id
FROM employees, departments
WHERE employees.department_id = departments.department_id;
join_rec c2%ROWTYPE; -- includes columns from two tables
BEGIN
NULL;
END;
/
%ROWTYPE属性と仮想列
%ROWTYPE
属性を使用して、仮想列を持つ表の行全体を表すレコード変数を定義する場合、そのレコードを表に挿入できません。かわりに、仮想列以外の各レコード・フィールドを表に挿入する必要があります。
例6-49 %ROWTYPEレコードの表への挿入(間違った例)
この例では、仮想列を持つ表の行全体を表すレコード変数を作成し、レコードに移入してから、そのレコードを表に挿入した結果、ORA-54013エラーが発生します。
DROP TABLE plch_departure; CREATE TABLE plch_departure ( destination VARCHAR2(100), departure_time DATE, delay NUMBER(10), expected GENERATED ALWAYS AS (departure_time + delay/24/60/60) ); DECLARE dep_rec plch_departure%ROWTYPE; BEGIN dep_rec.destination := 'X'; dep_rec.departure_time := SYSDATE; dep_rec.delay := 1500; INSERT INTO plch_departure VALUES dep_rec; END; /
結果:
DECLARE
*
ERROR at line 1:
ORA-54013: INSERT operation disallowed on virtual columns
ORA-06512: at line 8
例6-50 %ROWTYPEレコードの表への挿入(正しい例)
これは、仮想列以外の各レコード・フィールドを表に挿入することで、例6-49の問題を解決しています。
DECLARE dep_rec plch_departure%rowtype; BEGIN dep_rec.destination := 'X'; dep_rec.departure_time := SYSDATE; dep_rec.delay := 1500; INSERT INTO plch_departure (destination, departure_time, delay) VALUES (dep_rec.destination, dep_rec.departure_time, dep_rec.delay); end; /
結果:
PL/SQL procedure successfully completed.
%ROWTYPE属性と非表示列
%ROWTYPE
属性を使用して、非表示列を持つ表の行を表すレコード変数を定義しており、その後、非表示列を表示列に変更するとします。
「行の一部を表すことができるレコード変数の宣言」に示すように、カーソルとともにレコード変数を定義し、その後、非表示列を表示列に変更しても、レコード変数の構造は変わりません。
ただし、常に行の全体を表すレコード変数の宣言に示すようにレコード変数を定義し、SELECT
*
INTO
文を使用してレコードに値を代入した後、非表示列を表示列に変更すると、レコードの構造が変わります。例6-51を参照してください。
関連項目:
非表示列の概要は、『Oracle Database SQL言語リファレンス』を参照してください。
例6-51 非表示列の表示列への変更により影響を受ける%ROWTYPE
CREATE TABLE t (a INT, b INT, c INT INVISIBLE); INSERT INTO t (a, b, c) VALUES (1, 2, 3); COMMIT; DECLARE t_rec t%ROWTYPE; -- t_rec has fields a and b, but not c BEGIN SELECT * INTO t_rec FROM t WHERE ROWNUM < 2; -- t_rec(a)=1, t_rec(b)=2 DBMS_OUTPUT.PUT_LINE('c = ' || t_rec.c); END; /
結果:
DBMS_OUTPUT.PUT_LINE('c = ' || t_rec.c);
*
ERROR at line 5:
ORA-06550: line 5, column 40:
PLS-00302: component 'C' must be declared
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored
非表示列を表示列に変更:
ALTER TABLE t MODIFY (c VISIBLE);
結果:
Table altered.
前述の無名ブロックを繰り返す:
DECLARE t_rec t%ROWTYPE; -- t_rec has fields a, b, and c BEGIN SELECT * INTO t_rec FROM t WHERE ROWNUM < 2; -- t_rec(a)=1, t_rec(b)=2, -- t_rec(c)=3 DBMS_OUTPUT.PUT_LINE('c = ' || t_rec.c); END; /
結果:
c = 3
PL/SQL procedure successfully completed.