3.5.1 抽象データ型
ユーザ定義型である抽象データ型とルーチンを使用すると,複雑な構造を持つデータとその操作を独自に定義/利用できます。抽象データ型として列を定義すると,オブジェクト指向に基づく概念化・モデル化ができるようになります。また,オブジェクト指向に基づくソフトウェア開発手法を適用して,データベースの設計,UAPの開発及びメンテナンスの負担を軽減できます。
HiRDBでは,独自の抽象データ型やその構造を定義系SQLを使用して定義できます。抽象データ型は,数値型や文字型などのHiRDBの既定義型と同様に,表を構成する列のデータ型として扱えます。抽象データ型の値に対する操作も,定義系SQLを使用してルーチンとして定義できます。UAPでは,ルーチンを使用して抽象データ型に対する複雑な操作をSQLで記述できます。
抽象データ型とルーチン及びそれらについての特徴的な概念について,例を使用して説明します。
(1) 抽象データ型の定義
抽象データ型を使用して,従業員についての情報をデータベースで管理及び操作する例を示します。
従業員についての情報は,氏名,性別,入社年月日,役職,基本給などの情報から構成され,顔写真のような画像情報も従業員についての情報を構成する情報とします。また,従業員についての情報の操作として,勤続年数を算出するものとします。
この情報をデータベースで取り扱う場合の,データモデル化した抽象的な概念としての「従業員」は,その概念に共通した特性を示す属性「氏名」,「性別」,「入社年月日」,「役職」,「顔写真」,「基本給」から構成されると考えられます。また,「従業員」に対する操作「勤続年数」算出などについても,「従業員」の特性を示す操作であると考えられます。
「従業員」は,これらの特性(属性と操作)を一つのまとまりとみなします。
HiRDBでは,データベースで取り扱う実世界にある対象を抽象化した概念でとらえ,その概念を抽象データ型を使ってデータ型の一つにできます。
実世界の情報と抽象データ型による概念モデルを次の図に示します。
抽象データ型は,次に示す定義系SQLのCREATE TYPE によってデータベースに定義できます。
CREATE TYPE t_従業員 ( 氏名 CHAR(16), 性別 CHAR(1), 入社年月日 DATE, 役職 CHAR(10), 顔写真 BLOB(64K), 基本給 INTEGER, … FUNCTION 勤続年数 ( p t_従業員 ) RETURNS INTEGER BEGIN DECLARE working_years INTERVAL YEAR TO DAY; SET working_years = CURRENT_DATE - p..入社年月日; RETURN YEAR(working_years); END, … )
このように抽象データ型を定義すると,更にユーザがその抽象データ型の属性及び操作を指定して,新たなデータ型を定義できます。なお,操作はルーチンに定義できます。
(2) データ型としての抽象データ型
抽象データ型は,数値型や文字型などのHiRDBの既定義型と同様に扱えます。例えば,次に示す定義系SQLによって,抽象データ型 t_従業員 を列のデータ型として,表 社員表 を定義できます。
CREATE TABLE 社員表 ( 社員番号 INTEGER, 従業員 t_従業員 ALLOCATE (顔写真 IN (lobarea) ) )
抽象データ型の属性の中で,BLOB型の属性がある場合には,そのデータを格納するユーザLOB用RDエリアをCREATE TABLEのALLOCATEで指定します。上記の例では,t_従業員の属性である顔写真がBLOB型であるため,ALLOCATEを使用してユーザLOB用RDエリアlobareaに格納しています。抽象データ型を定義した社員表を次の図に示します。
(3) カプセル化
抽象データ型を使用した場合,アプリケーションでは,その抽象データ型に宣言されたルーチンを使用することで,個々の属性の詳細な構成やルーチンの実装を知らなくても,抽象データ型の値を扱えるようになります。例えば,次に示す操作系SQLで,t_従業員型の値を操作できます。
SELECT 社員番号, 従業員..氏名, 勤続年数(従業員) FROM 社員表
このように,抽象データ型によって,値の内部情報を意識させないようにして,外部的なインタフェースだけで値を扱えるようにすることをカプセル化といいます。
カプセル化の概要を次の図に示します。
(4) 抽象データ型の値
(a) 値の生成
抽象データ型と同じ名前で識別される引数のない関数を実行して,その抽象データ型の値を生成できます。例えば,t_従業員型 の場合には,関数 t_従業員() で,t_従業員型 の値を生成できます。このように,抽象データ型の値を生成する関数をコンストラクタ関数といいます。
BEGIN … SQL手続き文の始まり DECLARE p t_従業員; … t_従業員型の変数宣言 SET p = t_従業員(); … t_従業員型の値を生成し,変数に代入 SET p..氏名 = 'イトウエイイチ' … コンポネント指定による属性値の設定 RETURN p; … 関数の戻り値の返却(t_従業員型の値を返す) END … SQL手続き文の終わり
CREATE TYPEで抽象データ型をデータベースに定義すると,t_従業員()のような,データ型名が同じで引数のない関数が自動的に定義されます。このような関数を特にデフォルトコンストラクタ関数といいます。
(b) ユーザ定義のコンストラクタ関数
コンストラクタ関数をユーザが定義することもできます。CREATE TYPEのルーチン宣言で,定義する抽象データ型と同じ名前でその抽象データ型を戻り値の型とする関数を定義すると,コンストラクタ関数を定義できます。
CREATE TYPE t_従業員 ( 氏名 CHAR(16), 性別 CHAR(1), 入社年月日 DATE, 役職 CHAR(10), 顔写真 BLOB(64K), 基本給 INTEGER, FUNCTION t_従業員( p_氏名 CHAR(16), p_性別 CHAR(1), p_入社年月日 DATE, p_役職 CHAR(10), p_顔写真 BLOB(64K), p_基本給 INTEGER) RETURNS t_従業員 BEGIN DECLARE d_従業員 t_従業員; SET d_従業員 = t_従業員(); SET d_従業員..氏名 = p_氏名; SET d_従業員..性別 = p_性別; SET d_従業員..入社年月日 = p_入社年月日; SET d_従業員..役職 = p_役職; SET d_従業員..顔写真 = p_顔写真; SET d_従業員..基本給 = p_基本給; RETURN d_従業員; END, … )
例えば,ユーザ定義のコンストラクタ関数 t_従業員() を使用して,次に示す操作系SQLで値を生成し,データベースに格納できます。
INSERT INTO 社員表 VALUES ( 650056, t_従業員(:name AS CHAR(16), :sex AS CHAR(1), :yrs AS DATE, :post AS CHAR(10), :picture AS BLOB(64K) ,:salary AS INTEGER) )
コンストラクタ関数 t_従業員() によって値を生成し,列値として挿入した表 社員表を次の図に示します。
(5) 抽象データ型のナル値
HiRDBの既定義型と同様に,抽象データ型にもナル値を適用できます。例えば,前述の社員表について次に示す操作系SQLを実行した場合,列 従業員の値はナル値になります。
INSERT INTO 社員表(社員番号) VALUES ( 650056 )
一方,次に示す操作系SQLを実行すると,t_従業員型の全属性の値がナル値になります。なお,すべての属性の値がナル値であるような抽象データ型の値は,ナル値ではない値とみなされます。
INSERT INTO 社員表 (900123, t_従業員())
抽象データ型を定義した社員表でのナル値の扱いを次の図に示します。
例えば,次に示す操作系SQLを実行すると,列 従業員の値がナル値ではない従業員の社員番号が検索されるため,t_従業員型のすべての属性がナル値である従業員の社員番号は検索されます。
SELECT 社員番号 FROM 社員表 WHERE 従業員 IS NOT NULL
検索結果
900123
(6) 抽象データ型の値の操作
従業員に対して,勤続年数を算出するという操作を考えます。
HiRDBでは,CREATE TYPEのルーチン宣言で,抽象データ型の値に対する操作を定義できます。例えば,「勤続年数」算出や「報酬率」算出の操作を次に示す定義系SQLで定義できます。
CREATE TYPE t_従業員 ( 氏名 CHAR(16), 性別 CHAR(1), 入社年月日 DATE, 役職 CHAR(10), 顔写真 BLOB(64K), 基本給 INTEGER, … FUNCTION 勤続年数 ( p t_従業員 ) RETURNS INTEGER BEGIN DECLARE working_years INTERVAL YEAR TO DAY; SET working_years = CURRENT_DATE - p..入社年月日; RETURN YEAR(working_years); END, … )
このように,抽象データ型で定義したルーチンをその抽象データ型の値に対して使用できます。例えば,勤続年数が10年以上の社員の社員番号と氏名を検索するSQLは,次のように記述できます。
SELECT 社員番号, 従業員..氏名, 勤続年数(従業員) FROM 社員表 WHERE 勤続年数(従業員) >= 10