広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2010年04月28日

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

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


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


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


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

今回は、Javaのプログラムで、検索を行うSQL文を実行してみま
しょう。

以下がそのプログラム例です。

---------------------------------------------------
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class DbTest3 {
   public static void main(String[] args) {
      {
         try {
            Class.forName("org.h2.Driver");
            Properties props = new Properties();
            props.put("user", "sa");
            props.put("password", "");
            Connection conn = DriverManager.getConnection
            ("jdbc:h2:tcp://localhost/~/test", props);
            conn.setAutoCommit(false);
            Statement selectSql = conn.createStatement();
           
            ResultSet rs = selectSql.executeQuery("Select * FROM hotel");
            System.out.println("................................................");
            while (rs.next()) {
               System.out.println(rs.getInt("NUM") + ", " + rs.getString("Name") + ", " + rs.getString("address"));
            }
            selectSql.close();
            PreparedStatement selectSql2 = conn.prepareStatement("SELECT * FROM hotel where  address LIKE ?");
            selectSql2.setString(1, "%市川市某町%");
            ResultSet rs2 = selectSql2.executeQuery();
            System.out.println("................................................");
            while (rs2.next()) {
               System.out.println(rs2.getInt(1) + ", " + rs2.getString(2) + ", " + rs2.getString(3));
            }
            selectSql2.close();
            conn.close();
         }
         catch (SQLException exception) {
            exception.printStackTrace();
         }
         catch (Exception otherException) {
            otherException.printStackTrace();
         }
      }
   }
}
---------------------------------------------------
     
     
まず、22行目〜28行目

Statement selectSql = conn.createStatement();
ResultSet rs = selectSql.executeQuery("Select * FROM hotel");
System.out.println("................................................");
while (rs.next()) {
   System.out.println(rs.getInt("NUM") + ", " + rs.getString("Name") + ", " + rs.getString("address"));
}
selectSql.close();

を見てみましょう。
22行目の

Statement selectSql = conn.createStatement();

は以前出てきましたね。以前と違うのは23行目の行

ResultSet rs = selectSql.executeQuery("Select * FROM hotel");

です。
この文では、SQLのSELECT文を実行しようとしています。

ここでexecuteQuery()はSELECT文を実行する(RDBMSにこのSQL文を送り込んで実行
してもらう)ためのメソッドです。

Queryというのは元々は「質問」とか「問い合わせ」という意味ですね。コンピュー
ターの世界で普通、この単語を「検索」というふうに訳します。

そして、SQLのSELECT文がまさに検索を行うコマンドですから、SQLのSELECT文を
RDBMSに送り込んで実行するメソッドの名前もexecuteQuery(= 検索を実行する)
になっているのです。

この検索の結果は複数行になることが多いですから、結果を受け取る変数の型は
複数のデータを入れられるような形式のものが必要になります。

そのために用意されている型がResultSetです。

Resultは結果という意味ですが、Setは皆さんが数学の時間に習ったことのある
「集合」を意味する英単語です。

つまり、ResultSetは結果の集合体を意味する型なのです。

executeQuery()メソッドは結果をResultSetの型で返すので、23行目のように
ResultSet型の変数(ここではrs)で受け取る必要があります。


ここで23行目のSELECT文を再度よく見てみてください。

Select * FROM hotel

大文字と小文字が混ざっていますね。

以前お話したように、SQL文はデータ(カラムの値)の部分を除けば基本的には
大文字と小文字の区別がありませんので、このように大文字と小文字が混在し
た文にしても何も問題がありません。

┌補足─────────────────────────┐
一部、大文字と小文字が区別されるRDBMSもあります。
例えばUNIX(もしくはLinux)の環境下のMySQLでは、テーブル名
やデータベース名において大文字と小文字が区別されます。
ただし、MySQLでも設定次第で大文字と小文字を区別しないよう
にできます。
└───────────────────────────┘


次の24行目

System.out.println("................................................");

は標準出力を見やすくするために、区切り線のつもりで入れた文であり、あまり
意味はありません。

その次の25行目〜27行目

while (rs.next()) {
   System.out.println(rs.getInt("NUM") + ", " + rs.getString("Name") + ", " + rs.getString("address"));
}

は、検索の結果を標準出力に表示するためのものです。

while (論理式) {
   実行文
}

という構文は、「論理式と書いた部分がtrueの値を返す間はブロック({と}の間)
を繰り返し実行する」という操作を表します。

25行目〜27行目の例では、まずrs.next()の部分が実行され、その戻り値としてtrue
が返ってくる場合は、次の26行目

System.out.println(rs.getInt("NUM") + ", " + rs.getString("Name") + ", " + rs.getString("address"));

が実行されます。


ところで、ResultSetは検索結果のデータを(データベースのテーブルと同じように)
表の形式で保持します。

そしてこの表の中には現在何行目が選択されているかを示すポインターのような働き
をするものがあり、カーソル(cursor)と呼ばれています。

executeQuery()メソッドによって検索が行われてResultSetが戻り値として返された
ばかりのときには、カーソルは1行目(最初の行)の上にあります(0行目を指して
いる)。

25行目のrs.next()はResultSetのnext()メソッドを実行しているわけですが、この
メソッドはカーソルの位置を1行下に移動させるものです。

そして、rs.next()の1回目の実行で、カーソルはResultSetの1行目を指すことに
なります。

そして、その行が実在すると、rs.next()は戻り値としてtrueを返します。また、
もしその行が存在しない場合は、rs.next()は戻り値としてfalseを返します。

rs.next()がtrueの場合は、26行目が実行されることになりますが、26行目の中
のrs.getInt("NUM")は、rs(ResultSet)の中のカーソルが指す行のデータのうち、
NUMという名前のカラムの値をint型にして返す(戻り値がint型)メソッドです。

同様にrs.getString("Name")はNameという名前のカラムの値をString型にして返す
(戻り値がString型)メソッドです。

同じくrs.getString("address")は、addressという名前のカラムの値をString型に
して返す(戻り値がString型)メソッドです。


ここで、NUMやNameやaddressというカラム名の指定において、大文字、小文字を
不統一に使用していることにも注意してください。

これもSQL文が大文字と小文字を区別しないということに注意してもらうために
わざと不統一にしたものです。


while文はいわゆる「ループ」(loop = 元々は糸や紐などで作った「輪」のことを
意味するが、ソフトウエアにおいてはある条件の下で繰り返し実行される一連の
命令のことを意味する)の一種で、26行目の実行が終わると、再び25行目に戻っ
てrs.next()が実行されることになります。

そうするとカーソルはさらに次の行を指すことになり、その行が実在すると、再度
26行目が実行されることになります。

もし、25行目に戻ってrs.next()が実行された時点でfalseが返ってくると、もはや
26行目は実行されず、ブロックの外(27行目の}の下)に移ります。

つまり次の28行目が実行されることになります。

28行目

selectSql.close();

はいつものclose()メソッドですね。selectSqlにはもう用はなくなったので、
クローズしています。

次の29行目

PreparedStatement selectSql2 = conn.prepareStatement("SELECT * FROM hotel where  address LIKE ?");

は、前回に出てきたPreparedStatementですね。

今度は、SELECT文に「住所がxxxを含む場合」といった条件をつけ加えたいので、
xxxに相当する部分を例によって?で表現して、後で肉付けするために
PreparedStatementを使いました。

そしてその肉付けは、30行目

selectSql2.setString(1, "%市川市某町%");

で行っています。このsetString()メソッドも前回出てきましたね。ここでは?が
一つしかありませんから、setString()の第一引数は1しかありません。

第二引数の

"%市川市某町%

の前後にある「%」は、そこに何らかの任意の個数の文字があってもいいし無くて
もいいことをあらわす記号でしたね。これは

SELECT * FROM hotel where  address LIKE '%市川市某町%'

というようにLIKEの後ろに指定するカラムの値に使えるものです。

そうするとこのSELECT文は、addressのカラムの値の中に「市川市某町」という
文字列が含まれる行を検索してくれることになります。


次の31行目

ResultSet rs2 = selectSql2.executeQuery();

はこのPreparedStatementを使って検索(SELECT文の実行)を行うものです。

次の32〜36行目

System.out.println("................................................");
while (rs2.next()) {
System.out.println(rs2.getInt(1) + ", " + rs2.getString(2) + ", " + rs2.getString(3));
}
selectSql2.close();

は、24〜28行目と同じことをしています。
ただ、34行目

System.out.println(rs2.getInt(1) + ", " + rs2.getString(2) + ", " + rs2.getString(3));

はgetInt()、rs2.getString()、getString()がそれぞれ、引数にカラム名ではなく
数字が指定されていることに注意してください。

これらの数字はカラムの番号です。
最初にテーブルを作成(CREATE TABLE)したときにカラムを定義した順番に1、2、3と
いうカラムの番号がつきますので、カラム名の代わりにその番号を指定することも
できるのです。


では、実際にプログラムを作成して動きを確かめてみてください。

まず、一度H2 Consoleを起動して自分で直接SELECT文を入力して検索結果を確認し
た後、上記のプログラム例をEclipseに入力して実行してみましょう。

H2 Consoleで確認した検索結果と同じ内容のデータが出力されますね。

(続く)



========================================================
◆ 02.文法解説 [演算子]
========================================================

[算術用の二項演算子 -]

二項演算子の - は、引き算(減算)を行う演算子です。
減算の演算は2番目のオペランドの符号を反転させて加算の演算を行うのと同じ
です。

たとえば、

int y = x - 10;

という文は、演算子(-)の2番目のオペランドの符号を反転させ、
加算の演算子(+)を使い、

int y = x + (-10);

というふうにしても同じことになります。

というわけで、あとは加算の演算子を理解していればじゅうぶんだということに
なります。



----------------------------------------------
[算術用の二項演算子 *]

*演算子は掛け算(乗算)を行う演算子です。

この乗算の演算子においては、掛け算をするにあたって、オペランドの型に応じて
以下の型変換が行われます。(あくまで掛け算の計算のための一時的な変換であっ
てオペランドそのものが変わってしまうのではありません。)

(1) どちらかのオペランドがdouble型であれば、他方もdoubleに変換される。

(2) (1)に該当しない場合は、どちらかのオペランドがfloat型であれば、他方も
floatに変換される。

(3) (1),(2)のどちらにも該当しない場合は、どちらかのオペランドがlongであれば
他方もlongに変換される。

(4) (1),(2),(3)のどれにも該当しない場合は、両方のオペランドがintに変換される。

以上を簡単に表現すると「(絶対値が)より大きい数を含められる型のほうに変換
される」と覚えればじゅうぶんでしょう。

そして変換されたオペランドの値に対して掛け算が行われ、その計算結果が同じ型
のままで算出されます。

なお、計算結果がその型の最大値を超えてしまう場合は、その型では値が収まりきれ
ないため、誤った計算結果になってしまいます。しかも、このような場合でもエラー
あるいは例外(Exception)が発生するわけではありませんので、あらかじめ計算結果
の大きさを見込んだ上でじゅうぶん大きな値がはいる型にしておく必要があります。

なお、浮動小数点数の掛け算においては、この演算は一方または両方のオペランドが
正負の無限大やNaNの場合にも適用され、それぞれ以下のような結果となります。

(1) 両方または一方のオペランドがNaNの場合は、結果はNaN。

(2) 無限大と0の掛け算の結果はNaN。

(3) 無限大と0以外の数との掛け算の結果は無限大で、その符号は通常の数の掛け算の
ときと同じ(負*負は正、正*正は正、負*正は負、正*負は負)。


(続く)



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

下記のようなプログラムを作って、実行してみてください。

--------------------------------------------------------------------------
public class ArithmeticOperationTest2 {

   public static void main(String[] args) {
      System.out.println("-∞ * +∞ = " + (Float.NEGATIVE_INFINITY * Float.POSITIVE_INFINITY));
      System.out.println("+∞ * -∞ = " + (Double.POSITIVE_INFINITY * Float.NEGATIVE_INFINITY));
      System.out.println("+∞ * +∞ = " + (Float.POSITIVE_INFINITY * Double.POSITIVE_INFINITY));
      System.out.println("-∞ * -∞ = " + (Float.NEGATIVE_INFINITY * Float.NEGATIVE_INFINITY));
      System.out.println("10 * NaN = " + (10 * Float.NaN));
      System.out.println("NaN * 100 = " + (Double.NaN * 100));
      System.out.println("+∞ * NaN = " + (Float.POSITIVE_INFINITY * Double.NaN));
      System.out.println("+∞ * 1 = " + (Float.POSITIVE_INFINITY * 1));
      System.out.println("1 * -∞ = " + (1 * Float.NEGATIVE_INFINITY));
      System.out.println("-7 * ∞ = " + (-7 * Double.POSITIVE_INFINITY));
   }
}
--------------------------------------------------------------------------

結果はどうなりますか。



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