高校では写真部に所属するこうしろう,部費が足りないと言って学校のいろいろな行事を写した写真をCDに焼いて学内で販売,もとい配布しているらしい。本人曰く,材料費をもらっているだけだが,フィルム代ぐらいは稼いでいるのだろう。

 最近,こうしろうがいじっているカメラはアナログ一眼でも,デジタル一眼でもなくPETRIというクラッシックなカメラ,露出計もない完全マニュアル機だ。シャッターを押すとカシャーンと俺がカメラだと言いたげな強い音がする。ネットで1,200円で購入したらしい。写真とは洞窟探検のようなオタクの道である。

 EclipseによるJavaの勉強をしばらく休んでいたこうしろうであるが,模試が終わったといういかにも高校生らしい理由で久しぶりにモバイルPCの小さな画面にEclipseを立ち上げた。

 今,こうしろうはどのあたりにチャンレンジしているかと言うと,VE(Visual Editor)でSwingのJFrameクラスを継承するウィンドウを作り,jTextField などをjPanelに貼り付け,入力された値を使ってMySQLデータベースにアクセスするというコードを書いている。

   たとえば,こんな感じだ。データベースの検索処理ではテキストフィールドに入力した値やコンボボックスで選択した値を使って,SQL文を作成しMySQLデータベースに発行してレコードセットを取得する。取得したレコードセットはJTableに表示する。

 この検索用のSQL文を作成する処理はかなり面倒だ。ウィンドウ上の項目の値をWHERE条件句に指定してSELECT文を組み立てていくのだが,必ずウィンドウ上の全項目が指定されると決まっているなら簡単だ。でも,全項目の値がみんなわかっていれば検索する必要もないわけで,どの項目がどこまで入力されるのかはわからない,その都度違う。値が入力された項目だけをWHERE句に条件として作成していかなくてはならないが,このコードはなかなかスッキリとは書けないのだ。具体的にみていこう。SQL文を生成する処理はクラスのメソッドとして作成する。

----------------------------------------------------------

public void createSQL1(String shname,String tanka_low,
 String tanka_high,String kigou) 
 throws IllegalArgumentException {
 sql = "SELECT shcd,shname,tanka,kigou from t_syohin";
 String cond ="";
 String and ="";
 // 商品名 likeで部分一致
 if (shname.equals("")==false) {
  cond += " shname LIKE '%" + shname +"%'";
  and = " AND";
 }
 // 単価(以上)
 if (tanka_low.equals("")==false) {
  try {
   Integer.parseInt(tanka_low);
  } catch (NumberFormatException e) {
   throw new IllegalArgumentException("検索条件を正しく入力してください");
  }
  cond += and;
  cond += " tanka >= " + tanka_low ;
  and = " AND";
 }
 // 単価(以下)
 if (tanka_high.equals("")==false) {
  try {
   Integer.parseInt(tanka_high);
  } catch (NumberFormatException e) {
   // TODO 自動生成された catch ブロック
   // e.printStackTrace();
   throw new IllegalArgumentException("検索条件を正しく入力してください");
  }
  cond += and;
  cond += " tanka <= " + tanka_high ;
  and = " AND";
 }
 // 分類記号
 if (kigou.equals("")==false) {
  cond += and;
  cond += " kigou = '" + kigou + "'" ;
 }
 if (cond.equals("")==false) {
  sql = sql + " WHERE" + cond;
 }
 System.out.println(sql);
}

----------------------------------------------------------
 これまで私がよく使ってきた書き方である。select フィールド・リスト from テーブル名というテーブルからフィールドを取り出す部分をsqlに代入する(sqlはクラスの先頭でprivateで宣言している)。condにはWHERE句に続く条件を連結していく。各条件は絞り込み検索を行うためANDで結合していくので,andという変数も宣言している。引数として渡されたshname(商品名の一部)が””とイコールでないとき,つまり,何か入力されているとき,LIKE '%" + shname +"%'"として両横を%で囲み,テーブル上のフィールドshnameと部分一致の検索を行う。一つ検索条件を作ったので,次の条件を連結するために変数andに” AND”を代入する。

 二つ目の項目からは,cond変数にまずand変数を繋ぐ。一つ前の項目をcondに条件として作成している場合はand変数にはANDが入っているのが,そうでない場合は何も入っていないので空の文字列を連結することになる。これで,比較式がcondに作成されていて,そこに次の比較式を連結するときにANDで繋ぐという仕様が実現される。tanka(単価)については以上,以下という条件を作っている。最後に,cond変数に文字列が入っている場合,” WHERE”を付け,sqlと連結している。どの項目も入力されていないという場合もあるので,必ずWHEREを付けるわけにはいかない。

 この方法のミソはandという文字列を格納するための変数を用意しておき,比較式を一つ作成したら,その変数に” AND”を代入することだ。以下のようなSELECT文が作成される。
----------------------------------------------------------

SELECT shcd,shname,tanka,kigou 
  from t_syohin 
  WHERE shname LIKE '%メモリ%' AND tanka >= 3000 AND kigou = 'USBM'

----------------------------------------------------------
 欠点は,変数をいくつも使っており,パッと見にわかりにくいところだろうか。

メンバー変数sqlだけでWHERE条件式を連結していく方法もある。
----------------------------------------------------------

public void createSQL2(String shname,String tanka_low,
  String tanka_high,String kigou) 
  throws IllegalArgumentException {
 sql = "SELECT shcd,shname,tanka,kigou from t_syohin";
 // 商品名 likeで部分一致
 if (shname.equals("")==false) {
  sql +=" WHERE shname LIKE '%" + shname +"%'";
 }
 // 単価(以上)
 if (tanka_low.equals("")==false) {
  try {
   Integer.parseInt(tanka_low);
  } catch (NumberFormatException e) {
   throw new IllegalArgumentException("検索条件を正しく入力してください");
  }
  if (shname.length()!=0) {
   sql += " AND";
  } else {
   sql += " WHERE";
  }
  sql +=" tanka >= " + tanka_low ;
 }
 // 単価(以下)
 if (tanka_high.equals("")==false) {
  try {
   Integer.parseInt(tanka_high);
  } catch (NumberFormatException e) {
   // TODO 自動生成された catch ブロック
   // e.printStackTrace();
   throw new IllegalArgumentException("検索条件を正しく入力してください");
  }
  if ((shname.length() !=0) || (tanka_low.length() !=0)) {
   sql +=  " AND";
  }else {
   sql += " WHERE";
  }
  sql +=" tanka <= " + tanka_high ;
 }

 // 分類記号
 if (kigou.equals("")==false) {
  if ((shname.length() !=0) || (tanka_low.length() !=0)
    || (tanka_high.length() !=0)) {
   sql +=  " AND";
  }else {
   sql += " WHERE";
  }
  sql +=" kigou = '" + kigou + "'" ;
 }
 System.out.println(sql);
}


----------------------------------------------------------
 if (shname.length()!=0) のように,引数として渡された各項目に値が入っているかどうかを常に確かめて,”AND”でつなぐか,”WHERE”を付けるか判断する。欠点は検索条件の項目数が多いと
if ((shname.length() !=0) || (tanka_low.length() !=0) || (tanka_high.length() !=0)) とOR(||)条件をズラズラ記述しなければいけないところだ。

 次が折衷案である。
----------------------------------------------------------

public void createSQL3(String shname,String tanka_low,
  String tanka_high,String kigou) 
  throws IllegalArgumentException {
 sql = "SELECT shcd,shname,tanka,kigou from t_syohin";
 String where ="";
 // 商品名 likeで部分一致
 if (shname.equals("")==false) {
  where += " WHERE shname LIKE '%" + shname +"%'"; 
 }
 // 単価(以上)
 if (tanka_low.equals("")==false) {
  try {
   Integer.parseInt(tanka_low);
  } catch (NumberFormatException e) {
   // TODO 自動生成された catch ブロック
   // e.printStackTrace();
   throw new IllegalArgumentException("検索条件を正しく入力してください");
  }
  if (where.length()!=0) {
   where += " AND";
  } else {
   where += " WHERE";
  }
   where += " tanka >= " + tanka_low ;
 }
 // 単価(以下)
 if (tanka_high.equals("")==false) {
  try {
   Integer.parseInt(tanka_high);
  } catch (NumberFormatException e) {
   throw new IllegalArgumentException("検索条件を正しく入力してください");
  }
  if (where.length() !=0) {
   where +=  " AND";
  }else {
   where += " WHERE";
  }
  where += " tanka <= " + tanka_high ;
 }

 // 分類記号
 if (kigou.equals("")==false) {
  if (where.length() !=0) {
   where +=  " AND";
  }else {
   where += " WHERE";
  }
  where +=" kigou = '" + kigou + "'" ;
 }
 sql += where;
 System.out.println(sql);
}


----------------------------------------------------------
 変数whereにWHERE以下を全部,連結していく。” AND”で繋ぐか,” WHERE”を付けるかは項目数が多くても,if (where.length()!=0)だけで判断できる。ソースコードは前の2例に比べてスッキリしている。

 細かい話しなのでどうでも良いじゃないかと思われるかもしれないが,スッキリとしたコードを書くことで,プログラムのミスを探すバグ取りの時間が短縮できるというメリットがある。