広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2010年10月17日

    Java総合講座 - 初心者から達人へのパスポート
                  2009年11月開講コース 027号

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:vol.xxx(xxxは番号)が振られています。
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:xxx号(xxxは番号)が振られています。
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
(2009年11月開講コース)027号
 当記事はvol.028のリバイバル(revival)版です。
 vol.028の内容を最新のEclipse、Javaに基づいて書き直しています。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


========================================================
◆ 01.データベース(続き)
========================================================

今回は、前回のEMPLOYEEテーブルとDEPARTMENTテーブルを
実際に作成してみましょう。

まず、カラム名は以下のようにすることにします。

---------------------------------------------------
[EMPLOYEEテーブルのカラム]
社員番号、氏名、生年月日、所属部門コード
EMP_NUM, NAME, DATE_OF_BIRTH, DEPART_NUM
---------------------------------------------------

---------------------------------------------------
[DEPARTMENTテーブルのカラム]
部門コード、部門名、オフィス所在地
DEPART_NUM, DEPART_NAME, LOCATION
---------------------------------------------------

ところで、EMPLOYEEテーブルのDEPART_NUMはDEPARTMENTテー
ブルのDEPART_NUMを参照する外部キーでしたね。

このように外部キーを使って他のテーブルのデータを参照し
ている場合には、RDBMSが参照の整合性をチェックしますの
で、注意してください。

たとえば、もしEMPLOYEEテーブルを先に作成してデータを
入れようとすると、それが参照しているDEPARTMENTテーブ
ルのデータが存在しないので整合性が取れないことになり、
RDBMSがエラーを返します。

したがって、EMPLOYEEテーブルよりも、DEPARTMENTテーブル
のほうを先に作成してデータを入れておきます。
(以後、SQL文の最後には「;」を付けることにします。)

CREATE TABLE DEPARTMENT (DEPART_NUM INTEGER NOT NULL,
 DEPART_NAME CHAR(50), LOCATION CHAR(80),
 PRIMARY KEY (DEPART_NUM));

H2 Consoleを起動して、実際に上記のSQLを実行してみま
しょう。

続いて、DEPARTMENTテーブルにデータを入れておきましょ
う。

INSERT INTO DEPARTMENT  VALUES (0, '社長直属', 'Xビル3階');
INSERT INTO DEPARTMENT  VALUES (1, '総務課', 'Xビル2階');
INSERT INTO DEPARTMENT  VALUES (2, '営業課', 'Xビル1階');


では、次にEMPLOYEEテーブルを作成しましょう。

CREATE TABLE EMPLOYEE (EMP_NUM INTEGER NOT NULL, NAME CHAR(50),
 DATE_OF_BIRTH DATE, DEPART_NUM INTEGER NOT NULL, PRIMARY KEY (EMP_NUM),
 FOREIGN KEY (DEPART_NUM) REFERENCES DEPARTMENT (DEPART_NUM)  ON DELETE CASCADE);

ここで新しいキーワードが出てきましたので、説明しておき
ましょう。

上記のDATEというキーワードは標準のSQLで扱えるデータの型
の一つで、日付のデータを設定するための型になっています。
詳しくは後述します。

上記のFOREIGN KEYというのは外部キー(foreign key)を意味
するキーワードでその右側の括弧の中にDEPART_NUMと書いてあ
るのは、このテーブル内のDEPART_NUMというカラムが外部キー
になっていることを指定しているものです。

そしてその外部キーがどのテーブルのどのカラムを参照してい
るのかを指定しているのがその右側のREFERENCESというキーワー
ドです。

そしてREFERENCESの右側に

DEPARTMENT (DEPART_NUM)

と書いてあるのは、DEPARTMENTテーブルのDEPART_NUMというカラ
ムを参照することを指定するものです。

また、さらにその右側に書いてある

ON DELETE CASCADE

というキーワードはこの外部キーが参照しているDEPARTMENTテー
ブルにおいて、ある行が削除されたとき、その行を参照していた
(つまりその行のDEPART_NUMカラムの値を外部キーの値として持っ
ていた)EMPLOYEEテーブルの行も削除することを意味します。

たとえば、DEPART_NUMが1の'総務課'が廃止されたとして、
DEPARTMENTテーブルの中の'総務課'の行を削除すると、自動的に
EMPLOYEEテーブルの中のDEPART_NUMが1の行、つまり'総務課'に所属
していた社員の行も削除されることになります。

これは参照の整合性が維持されている例としてはいいのですが、
総務課が廃止されたらそこに所属していた社員も全員首になると
いうことですから(冗談ですが)、あまりいい例ではありませんね。

というわけで、少し変更しましょう。

通常は、部署が廃止されてもそこに所属していた社員が別の部署に
異動になるか、さもなければしばらくの間は社長直属などの一時的
な所属があてられることになるでしょうから、そのように指定を
変更してみましょう。

さきほどの

ON DELETE CASCADE

の代わりに

ON DELETE SET DEFAULT

を指定し、

DEPART_NUM INTEGER NOT NULL

の右側にDEFAULT 0をつけて

DEPART_NUM INTEGER NOT NULL DEFAULT 0

という指定に書き換えてみましょう。

下にSQL文全体を掲載します。

CREATE TABLE EMPLOYEE (EMP_NUM INTEGER NOT NULL,
 NAME CHAR(50), DATE_OF_BIRTH DATE,
 DEPART_NUM INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (EMP_NUM),
 FOREIGN KEY (DEPART_NUM) REFERENCES DEPARTMENT (DEPART_NUM)  ON DELETE SET DEFAULT);

この

DEPART_NUM INTEGER NOT NULL DEFAULT 0

の指定によって、DEPART_NUMカラムについてはデフォルト値
(値を明示しないときに自動的に設定される値)が0になり、
FOREIGN KEYの

ON DELETE SET DEFAULT

の指定によってDEPARTMENTテーブルの行の削除時にはそれを
参照しているEMPLOYEEテーブルの行が削除されるのではなく、
EMPLOYEEテーブルの該当する行のDEPART_NUMカラムの値がデ
フォルト値(ここでは0)に設定されることになります。

そして、社長直属というのも一つの部署とみなしてその
DEPART_NUMの値を0としておくと、他の部署が廃止されたとき
にはその部署に所属していた社員は自動的に社長直属に変更さ
れるということになります。

では、上のCREATE TABLE文をH2 Consoleに入力してください。

続いて、EMPLOYEEテーブルにデータを入れておきましょう。

INSERT INTO EMPLOYEE  VALUES (1, '舟木和子', '1970-11-12', 1);
INSERT INTO EMPLOYEE  VALUES (2, '安部泰三', '1960-10-12', 1);
INSERT INTO EMPLOYEE  VALUES (3, '長内順平', '1986-08-12', 2);

上記のSQL文を見ればわかるように、先ほどのDATEという型に
対する値は

'YYYY-MM-DD'

という形式で指定することになっています。
ここで、YYYYは4桁の(西暦の)年の数字、MMは2桁の月の数字、
DDは2桁の日の数字を意味します。

たとえば1970年11月12日は'1970-11-12'と指定するわけです。

では、次に

DELETE  FROM DEPARTMENT WHERE DEPART_NUM=2;

を実行することによってDEPARTMENTテーブルからDEPART_NUMの値
が2の行を削除してみてください。
そして SELECT * FROM EMPLOYEE で、EMPLOYEEテーブルの中の
DEPART_NUMの値が2だった行、つまり'長内順平'さんの行を見て
みるとDEPART_NUMの値が自動的に0に変わることがわかりますね。


しかし、ここで、「社長直属を一つの部署とみなすのはおかしい
のではないの?」「社長直属って部署じゃないんじゃないの?」と、
疑問を呈する人もいるかもしれません。

もし、そういうことにこだわるのであれば、次のような指定も可能
です。

CREATE TABLE EMPLOYEE (EMP_NUM INTEGER NOT NULL, NAME CHAR(50),
 DATE_OF_BIRTH DATE, DEPART_NUM INTEGER, PRIMARY KEY (EMP_NUM),
 FOREIGN KEY (DEPART_NUM) REFERENCES DEPARTMENT (DEPART_NUM)  ON DELETE SET NULL);

このSQL文ではDEPART_NUMにNOT NULLの指定がないので、DEPART_NUM
にはNULL(データが空)も許容されます。
また、 FOREIGN KEY (DEPART_NUM) のREFERENCESに対して
ON DELETE SET NULLが指定されているので、DEPARTMENTテーブル
の行の削除時にはそれを参照しているEMPLOYEEテーブルの該当す
る行のDEPART_NUMカラムの値がNULL(空っぽ)に設定されること
になります。

したがって、DEPART_NUMカラムの値がNULL(空っぽ)の場合を
社長直属と定義することにすると、先ほどのように社長直属を
(DEPART_NUMが0の)一つの部署とみなしてDEPARTMENTテーブル
にデータを入れておくような必要はなくなります。

ただし、この場合はDEPART_NUMの値を設定し忘れてもDEPART_NUM
の値がNULLになってしまい、データ入力する人が間違えると、
やたらに社長直属の社員が増えるということにもなりかねません。

というわけで、NULLの使用はできるだけ避けたほうがいいのです。

主キーや外部キーはNOT NULLを指定してNULLを使用できないように
するのが原則です。

NOT NULLを指定しておけば、データ入力時に値を設定し忘れると
エラーになるので気が付きます。


では、次に、こうして作られたEMPLOYEEテーブルとDEPARTMENTテー
ブルを組み合わせてデータを表示したいときにはどうするのかお話
しましょう。

たとえば、社員のデータを表示したいと思って

SELECT * FROM EMPLOYEE

というSQL文を実行しても、所属部署については数字しか表示され
ませんが、所属部署についての詳しいデータをDEPARTMENTテーブル
から取ってきて社員のデータと一緒に並べたいときには、たとえば
次のようなSQL文を指定します。

SELECT * FROM EMPLOYEE, DEPARTMENT WHERE EMPLOYEE.DEPART_NUM = DEPARTMENT.DEPART_NUM;

ここで、FROMの後ろにEMPLOYEE, DEPARTMENTというようにテーブル名
を複数並べると、複数のテーブルからデータを取り出すことができ
ます。

また

WHERE EMPLOYEE.DEPART_NUM = DEPARTMENT.DEPART_NUM

はEMPLOYEEテーブルのDEPART_NUMカラムの値とDEPARTMENTテーブル
のDEPART_NUMカラムの値を照らし合わせて、それらが互いに等しい行
のデータを取り出すことを意味します。

しかし、こうやってデータを取り出すと、返ってきたリストの中には
EMPLOYEEテーブルのDEPART_NUMカラムの値とDEPARTMENTテーブルの
DEPART_NUMカラムの値の両方が含まれ、それらは互いに同じ値ですから
無駄でうっとうしく見えるかも知れません。

うっとうしいと思う人は、下記のように、表示したいカラムだけを
一つ一つ明示しましょう。

SELECT EMP_NUM, NAME, DATE_OF_BIRTH, EMPLOYEE.DEPART_NUM,
 DEPART_NAME, LOCATION  FROM EMPLOYEE, DEPARTMENT
 WHERE EMPLOYEE.DEPART_NUM = DEPARTMENT.DEPART_NUM;

このとき、DEPART_NUMカラムのようにEMPLOYEEテーブルとDEPARTMENTテー
ブルのどちらにも同名で含まれるカラムについては、EMPLOYEE.DEPART_NUM
のように「テーブル名.カラム名」の形式でテーブル名も明確にしてお
きます。



次回は、データベースをもう少し複雑にして実用的なレベルに近づけ、
データベースを使ったJavaのアプリケーション開発の説明に入っていき
ます。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2010 Future Lifestyle Inc. 不許無断複製