広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2010年03月31日

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

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


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


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


========================================================
◆ 01.データベース
========================================================

SQLは国際的に標準化されているといいましたが、実際には各メー
カーは独自の機能を追加して標準のSQLを拡張したり、あるいはSQL
の標準を完全には満たしていなかったりすることが多いので、要
注意です。

メーカー独自の機能(標準でないSQL構文)については、通常、RDBMS
のマニュアル(取り扱い説明書のこと)に記載されていますので、
実際の使用にあたってはマニュアルを調べて確認しておく必要があ
ります。
そして、なるべくメーカー独自の機能は使わずに、標準的な機能を
利用することが望ましいです。
(例えば、RDBMSのメーカーの最大手として知られるO社では独自の
SQL構文がよく使われています。そして、こういった独自の構文を
頻繁に使ったアプリケーションは、何らかの理由で他のメーカーの
RDBMSに置き換えたいと思っても、SQL文を書き換えるのに苦労する
ことになり、簡単に置き換えることができません。)


では以下にSQLの例を上げながら、リレーショナル・データベースを
具体的に説明していきましょう。


(1) テーブルの作成/削除

リレーショナル・データベースではデータを表の形式で保管し管理し
ますので、データの読み書きをするためには、その前に表が作られ
ていなければなりません。

この表のことを英語でtable(テーブル)と言いますので、データベー
スの表のことを日本でもテーブルと呼んでいます。
(食卓などのテーブルと同じ単語で紛らわしいですね。)

さて、ホテルの情報を管理するための簡単なテーブルを用意すると
しましょう。

テーブルを作成するためには、例えば以下のようなSQL文を使用します。

CREATE TABLE hotel (num INTEGER NOT NULL, name CHAR(50), address CHAR(80), PRIMARY KEY (num))

上記のSQLのうち、大文字で書いたものはSQLのキーワードで、小文字で
書いたものは私が勝手に付けた名前です。

一般にSQLでは大文字と小文字の区別はありません(ただし、名前の大文字
と小文字を区別するような指定も可能ですし、メーカーによってはデフォルト
で大文字と小文字が区別される場合もあります)。

上のSQL文は、hotelという名前のテーブルを作成し、その中でnumという
名前の列(column=カラムともいう)とnameという名前のカラム(列)と
addressという名前のカラム(列)を用意することになります。

ここでは、nameはホテルの名前を入れるための列として、また、addressは
ホテルの住所を入れるための列として用意しました。

numというのはそれぞれ別々のホテルに異なる番号をつけるためのもので、
要するにホテルを識別するための番号を入れるために用意した列です。

そして、numの後ろのINTEGER NOT NULLというのは、このnumという列には整数
(integer)を入れなければならず、かつ空っぽであってはいけない(not null)
ということを指定するキーワードです。
つまりnumは整数型で、かつ必ず値を入れなければならないことを指定したもの
です。

nameの後ろのCHAR(50)はこの列が文字(character)型で、50バイト(英語なら
50文字入る)のデータ記憶場所を確保することを指定したものです。ここには
NOT NULLの指定がありませんから、この列は空っぽでもかまわないということに
なります。

同様にaddressの後ろのCHAR(80)は文字型のデータで80バイトまで収容可能な
記憶場所を確保することになります。

ところで、データベースの機能の一つに「データが重複することを防ぐ」という
働きがあります。

たとえば、同じホテルのデータを間違えて2回登録したりすると、問題が生じる
可能性があります(例えば、後でホテルのデータに間違いが見つかって修正した
とすると、重複したデータのうち一方だけ修正すると次にデータを読み出すとき
に修正していないほうのデータを読み出してしまう恐れがある)から、同じホテ
ルのデータは1回しか登録できないようにしておく必要があります。

そのときに、「同じホテル」をどうやって判断するかという問題があります。
ホテル名(上のSQL文のname)で判断しようと思っても、たとえば東京と大阪に
それぞれ「ベストホテル」という同名の無関係なホテルがあった場合に困ります。

一般には名前ではなく、なんらかの識別番号を割り当てて区別します。

たとえば東京の「ベストホテル」は001番で大阪の「ベストホテル」は011番と
いうようにそれぞれのホテルにユニークな(唯一のという意味)識別番号を割り
当てることによって、RDBMSが明確にデータの重複性をチェックすることが可能に
なります。

上のSQL文の中のPRIMARY KEY(プライマリー・キー)というキーワードはこの
識別番号を指定するものです。
PRIMARY KEYは日本語では主キーまたは基本キーと呼ばれ、これを指定しておくと
データが重複しないようにチェックしてくれます。
(もし間違えて重複したデータを入れようとすると、RDBMSがエラーを返して
くれます。)

上のSQL文の中のPRIMARY KEY (num)という指定は、numというカラムを主キーと
して使用することを意味します。

なお、主キーは必ずしも番号である必要はなく、文字でもかまいません。


┌補足─────────────────────────┐
テーブルを作成するための上記のSQL文もう少し詳しく説明すると、下のような
形式になる。

   CREATE TABLE tablename (colname data-type, colname data-type, ..., PRIMARY KEY (key-colname))

ここでtablenameはテーブル名、colnameはカラム名(列名)、key-colnameは主キー
にしたいカラム名(複数指定可能)、data-typeは各カラムのデータの型である。

テーブル名は、「スキーマ名.テーブル名」というふうに頭にスキーマ名.とピリオド
を付けることがあるが、細かい説明は省略する。

データの型には、
   CHARACTER(integer)またはCHAR(integer)・・・固定長の文字列用
         ここで、括弧の中のintegerは文字数を表わす整数
   VARCHAR(integer)・・・可変長の文字列用
         ここで、括弧の中のintegerは最大文字数を表わす整数
   DECIMAL(integer,integer)またはDEC(integer,integer)・・・十進数用。
         ここで、括弧の中の最初のintegerは有効桁数を表わす整数、
         次のintegerは少数点以下の桁数の整数である。
         DECIMAL(p,0)をDECIMAL(p)、また、DECIMAL(5,0)をDECIMALと略すことができる。
         DECIMALやDECの代わりにNUMERICやNUMを使ってもよい。
   FLOAT・・・浮動小数点数用

など様々な型がある。
└───────────────────────────┘

逆に、テーブルを削除するためには、以下ようなSQL文を使用します。

   DROP TABLE tablename


(2) データの追加

テーブルにデータを追加するには例えば次のようなSQL文を使います。

INSERT INTO hotel  VALUES (1, '有名ホテル', '市川市なんとか町100-100-100')

この文はhotelという名前のテーブルに(1, '有名ホテル', '市川市なんとか町100-100-100')
という値の行を挿入することをRDBMSに命令します。

括弧の中のデータはCREATE TABLEのときの順番で、前から順番にnum, name,
addressの列にデータが入れられることになります。

なお、上記SQL文を見ればわかるように、文字のデータはシングル・クウォーテー
ション(')で囲みます。

上のSQL文でテーブルに1行のデータが挿入されることになります。

同様に次のSQL文を入力すると、もう1行データが挿入されることになります。

INSERT INTO hotel  VALUES (2, '無名ホテル', '市川市かんとか町200-200-200')

もし、これを

INSERT INTO hotel  VALUES (1, '無名ホテル', '市川市かんとか町200-200-200')

としてしまったら、すでに存在するデータと主キーが重複しますので、重複した
データと判断され、RDBMSがエラーを返してきて、データの挿入は行われません。


┌補足─────────────────────────┐
テーブルにデータ(行)を追加するための上記のSQL文もう少し詳しく説明すると、
下のような形式になる。

   INSERT INTO tablename VALUES (coldata,coldata,...)

なお、ここでは全てのカラムに値を設定する必要がある。
もし特定のカラムだけ設定したい場合は

   INSERT INTO tablename (colname,colname,...) VALUES (coldata,coldata,...)

というふうにcolnameにカラム名を指定する。
└───────────────────────────┘


(3) データの検索

テーブルからデータを検索するには例えば次のようなSQL文を使います。

SELECT num, address FROM hotel WHERE name = '有名ホテル'

このSQL文ではname列に「有名ホテル」という文字列のデータが入っている行
が検索され、その行のnum列の値とaddress列の値が取り出されて表示されるこ
とになります。


┌補足─────────────────────────┐
テーブルからデータを検索するための上記のSQL文もう少し詳しく説明すると、
下のような形式になる。

   SELECT select-list FROM tablename WHERE search-condition

ここでselect-listは、取り出したいカラムをカラム名で指定するものである。

カラム名が複数あるときは、コンマで区切る。

また、tablenameは、検索したいテーブル名である。

search-conditionつまりWHEREの中身は検索条件を表現するものであり、例えば
以下のような形式で記述できる。

   (1) カラムが特定の値を持つものを検索したい場合: colname = coldata AND colname = coldata ...
       例えば、「name = '有名ホテル' AND num = 1」とすると、nameカラムの値が「有名ホテル」で、かつ
       numカラムの値が1であることを検索条件として設定することになる。

   (2) カラムが特定の値を含むものを検索したい場合: colname LIKE %coldata% OR colname LIKE %coldata% ...
       例えば、「name LIKE '%有名%' OR address LIKE '%市川%'」とすると、
nameカラムの値の中に「有名」が含まれるか、あるいはaddressカラムの値の中に
「市川」が含まれることを検索条件として設定することになる。
       つまり、LIKEはあいまい検索を指定し、%はそこにどんな値が来てもよいことを示す。

(1)、(2)いずれの場合でも、複数の条件を組合せるためにANDとORのどちらを使用し
てもよいし、他に否定を表わすNOTも使用できる。
また、条件を記述する論理演算子には、上記のLIKEや=の他に、>、<、<=、>=、><、
<>など様々なものがある。
└───────────────────────────┘


(4) データの更新

データを更新(どこかの行のデータを一部変更すること)するには例えば
次のようなSQL文を使います。

UPDATE hotel SET address = '船橋市かんとか町200-200-200'  WHERE num = 2

このSQL文はhotelテーブルの中でnum列の値が2の行を探し、その行のaddress列
の値を「船橋市かんとか町200-200-200」に変更することをRDBMSに命令します。


┌補足─────────────────────────┐
データ(行)の特定のカラムを更新(変更)するための上記のSQL文をもう少し詳しく
説明すると、下のような形式になる。

   UPDATE tablename SET colname = expression, colname = expression, ... WHERE search-condition

ここで、expressionは更新したい各カラムの値または式を意味する。

例えば、ある社員(EMPLOYEE)のデータベース・テーブルにおいて、部門コード(DEPCODE)
が5で始まる社員の給料(SALARY)を1.1倍に上げたい時は、

   UPDATE EMPLOYEE SET SALARY = SALARY * 1.1 WHERE DEPCODE LIKE '5%'

というふうにSALARYのカラムを更新すればよい。ここで、*は乗算を表わす演算子で
ある。
└───────────────────────────┘


(4) データの削除

データ(行)を削除するには例えば次のようなSQL文を使います。

DELETE FROM hotel WHERE num = 2

このSQL文はhotelテーブルの中でnum列の値が2の行を探し、その行を削除する
ことをRDBMSに命令します。


(5) コミットとロールバック

以上のSQL等を使ってテーブルへの追加/更新/削除作業を行った後、それらを
正式の作業として宣言することをコミットと呼びます。

コミットは、COMMITというSQL文によって、実行されます。

また、コミットしていない作業については、取消しを行うこともできます。

取消しは、ROLLBACKというSQL文によって、実行されます。

つまり、COMMITを実行する前のINSERT、UPDATE、DELETEのSQLの命令は、ROLLBACK
を実行すると全て無効となります。

なお、一般に追加/更新/削除作業を行ってからCOMMITやROLLBACKするまでは
データにロックがかかるので、その間、他のアプリケーションから同じデータに
アクセスすることはできません。


今回は、ここまでにします。

次回は、オープン・ソース(無料)のRDBMSをインストールして、実際に上記のSQLを
試してみることにしましょう。


来週をお楽しみに。



========================================================
◆ 02.文法解説 [配列型]
========================================================

配列(array)はメモリー上に複数のオブジェクトの参照を連続して配置記憶する
方法であり、それぞれの要素(オブジェクト)には、0から始まる整数の番号が振られ、
0番目の要素、1番目の要素、・・・というふうに呼ばれます。

要素の番号は[]で囲んで表記します。([]はコンピューターの表示環境によっては
長方形の図形のように見えるかもしれませんが、実際は、[ ]という2つの文字(記号)
です。)

例えば、3個の要素を持つ、String型の配列を用意するためには

String [] str = new String[3];
(昔はString str []と書いていたが、現在はString [] strのように変数名を最後に書く
ことが推奨されている。)

というように変数を宣言することができますが、このように[]をつけて宣言した変数
(ここではstrという変数)の型は配列型と呼ばれます。

上記の文では、左辺の

String [] str

はString型でかつ配列型(Stringの配列型)の変数strを宣言しており、右辺の

new String[3]

は、String型の3個の要素を持つ配列を生成していることを意味します。

間違いやすいことは、右辺をインスタンスの生成と勘違いしてしまうことです。

上記の文では、strにはString型のインスタンスが代入されるわけではありません
ので、注意してください。

右辺にあるString[3]はコンストラクターではありません。コンストラクターなら
[ ]の代わりに( )と書かなければなりません。
String[n]と言うのはn個の要素を持つString型の配列を意味します。

Javaでは配列もオブジェクトとして扱われており、上の代入演算はその配列のアドレス
(前回もお話したように実アドレスではないが、わかりやすくするためにアドレスと
呼んでおく)を変数strに代入するという意味になります。

この文だけではまだStringのインスタンスは生成されていないことに注意して下さ
い。

Stringのインスタンスを生成して代入するところまで書くと、例えば次のように
なります。

String [] str = new String[3];
str[0] = "1つ目の要素";  // (1)
str[1] = "2つ目の要素";  // (2)
str[2] = "3つ目の要素";  // (3)

こうすると、(1)ではstr変数が指し示す配列の1番目の要素に"1つ目の要素"という
String型のインスタンスが代入される(String型のインスタンスのアドレスがstr[0]に
入る)ことになります。

以下同様に(2)ではstr変数が指し示す配列の2番目の要素に"2つ目の要素"という
String型のインスタンスが代入され、(3)ではstr変数が指し示す配列の3番目の
要素に"3つ目の要素"というString型のインスタンスが代入されることになりま
す。

なお、上記の4行を1行にまとめたい場合は、
String [] str = new String[]{"1つ目の要素", "2つ目の要素", "3つ目の要素"};
と書くこともできます。

String型なら上記のようにリテラルの指定で即インスタンスが生成されますが、
一般のクラスの場合はコンストラクターを呼び出してインスタンスを生成する
必要があります。

たとえば、

Human [] humans = new Human[3];
humans[0] = new Human(1985, 2, 3);
humans[1] = new Human(1975, 4, 11);
humans[2] = new Human(1997, 7, 20);

という具合です。
なお、上記の4行を1行にまとめたい場合は、
Human [] humans = new Human[]{new Human(1985, 2, 3), new Human(1975, 4, 11), new Human(1997, 7, 20)};
と書くこともできます。


配列はプリミティブ型に対しても同様に指定できます。

たとえば、int型に対しては

int [] nums = new int[3];
nums[0] = 10;
nums[1] = 15;
nums[2] = 20;

という具合です。上記のようにプリミティブ型の場合はもちろんコンストラクター
の呼び出しなどはありません。
なお、上記の4行を1行で、
int [] nums = new int[]{10, 15, 20};
と書くこともできます。

この[]は複数(n個)指定することもでき、その個数に応じてn次元配列と呼ばれる
ことがあります。

例えば、2次元の配列を考えてみましょう。

int [][] g = new  int[2][3];

というような配列型の宣言ができ、
g[0][0] = 1;
g[0][1] = 2;
g[0][2] = 3;
g[1][0] = 4;
g[1][1] = 5;
g[1][2] = 6;
というように各要素にint型の値を代入できます。
なお、上記の2次元配列の代入演算をまとめて、
g = new  int[][]{{1, 2, 3}, {4, 5, 6}};
と書くこともできます。
(あるいは、宣言文から全部まとめて書きたい場合は、
int [][] g = new  int[][] {{1, 2, 3}, {4, 5, 6}};
と書くこともできます。)


Javaでは配列はオブジェクトなので、属性もメソッドも持っています。

たとえば、上記のgという配列の要素数は配列のlengthという属性変数に
セットされており、

int  gLength = g.length;

という文を書くと、gLengthに配列gの要素数が代入されます。

また、メソッドとしては、たとえばclone()というのがあり、これによって
配列の複製を作ることができます。


詳しくは、また後で説明します。



======================================================
◆ 03.演習問題
======================================================

下記のようなクラスを作成して実行してみて下さい。

-------------------------------------------------------
package jp.co.flsi.lecture.human;

public class ArrayCloneTest {

   public static void main(String[] args) {
      int [] nums = new int[]{10, 15, 20};
      int [][] g = new  int[][] {{1, 2, 3}, {4, 5, 6}};
      int [] numsClone = nums.clone();
      numsClone[1] = 15000000;
      System.out.println("numsClone.length = " + numsClone.length);
      System.out.println("numsClone[0] = " + numsClone[0]);
      System.out.println("numsClone[1] = " + numsClone[1]);
      System.out.println("numsClone[2] = " + numsClone[2]);
      System.out.println("nums.length = " + nums.length);
      System.out.println("nums[0] = " + nums[0]);
      System.out.println("nums[1] = " + nums[1]);
      System.out.println("nums[2] = " + nums[2]);
      int [][] gClone = g.clone();
      gClone[1][1] = 50000;
      System.out.println("gClone.length = " + gClone.length);
      System.out.println("gClone[0].length = " + gClone[0].length);
      System.out.println("gClone[0][0] = " + gClone[0][0]);
      System.out.println("gClone[0][1] = " + gClone[0][1]);
      System.out.println("gClone[0][2] = " + gClone[0][2]);
      System.out.println("gClone[1][0] = " + gClone[1][0]);
      System.out.println("gClone[1][1] = " + gClone[1][1]);
      System.out.println("gClone[1][2] = " + gClone[1][2]);
      System.out.println("g.length = " + g.length);
      System.out.println("g[0].length = " + g[0].length);
      System.out.println("g[0][0] = " + g[0][0]);
      System.out.println("g[0][1] = " + g[0][1]);
      System.out.println("g[0][2] = " + g[0][2]);
      System.out.println("g[1][0] = " + g[1][0]);
      System.out.println("g[1][1] = " + g[1][1]);
      System.out.println("g[1][2] = " + g[1][2]);
   }

}
-------------------------------------------------------

実行した結果から、配列のclone()メソッドについて、1次元の配列と2次元の配列
の結果を見比べて、何かに気づいたことと思います。
何に気がつきましたか?そしてそれはなぜだと思いますか?



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      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. 不許無断複製