mucchinのAndroid戦記

Androidアプリのデータ保存方法の一つ「SQLite」の使い方 レコード検索編

Androidのデータベース「SQLite」の使い方は?

今回は、以下の記事の続編になります。
Androidアプリのデータ保存方法の一つ「SQLite」の使い方 SQLiteOpenHelper編
Androidアプリのデータ保存方法の一つ「SQLite」の使い方 行の追加・更新・削除編

これまで、データベースのオープンと、レコードの追加・更新・削除についての説明をしました。
今回は、SQLでいうselect文、レコードの検索について説明していきます。
一概にはいえませんが、データベースを取り扱う上で、コード的には最も実装する場面が多いのが、このselectじゃないかなと思います。


これから示すサンプルコードでは、「Androidアプリのデータ保存方法の一つ「SQLite」の使い方 SQLiteOpenHelper編で掲載しているサンプルコードにて、既にSQLiteDatabase型インスタンスを生成しているものとします。
変数名は、sdbとします。
なお、テーブル定義は、テーブル名は「bookmarklist」で、_id列とbookmark列の2列が存在する事とします。
※_id列については、別記事「Androidアプリで使用するSQLiteのテーブル作成時の注意点」を参照してください。
レコードの検索を行った後、検索結果は、Cursorというインスタンスとして返されてきます。
このCursorインスタンスの取得方法は、大きく2通りありますので、まずはその方法を紹介します。

SQLiteDatabase.query()の使い方

まずは一つ目の、SQLiteDatabase.query()メソッドの使い方を説明します。


final String[] columns = new String[]{“_id”,”bookmark”};
String where = “bookmark like ?”;
String param = “%android%”;
Cursor c =
   sdb.query(“bookmarklist”,columns,where,new String[]{param},
          null,null,”_id desc”,”10″);
SQLiteDatabase.query()メソッドの第一引数はテーブル名です。
第二引数は、取得する列名(カラム名、フィールド名)の配列を指定します。
第三引数、第四引数は取得するレコードの条件を指定します。
今回は、bookmark列の文字列に、「android」という文言が含まれる文字列、という条件にしています。
第五引数は、group by句を指定します。
第六引数は、Having句を指定します。
第七引数は、order by句を指定します。
第八引数は、limit句(取得するレコードの上限数)を指定します。
使わない場合は、nullを指定します。
今回の処理をSQL文で表現すると、以下のようになります。
select _id,bookmark
from bookmarklist
where bookmark like ‘%android%’
order by _id desc
limit 10
Cursorオブジェクトの操作方法は後述します。

SQLiteDatabase.rawQuery()の使い方

それでは次は、rawQuery()メソッドの使い方を説明します。
rawQuery()メソッドは、文字通り、生のクエリを使用します。


String sqlstr = “select _id,bookmark ” +
          ”from bookmarklist ” +
          ”where bookmark like ‘%android%’ ” +
          ”order by _id desc ” +
          ”limit 10″;
Cursor c = sdb.rawQuery(sqlstr);
SQLiteDatabase.rawQuery()メソッドの引数は、SQL文です。
個人的には、先ほどのquery()メソッドより使いやすいと思うんですが、どうでしょうか。
query()メソッドは、どの引数に何のパラメータを与えればよかったんだっけ?といちいち調べないといけなさそうなのですが、rawQuery()メソッドは明確です。
それに、inner joinやleft outer join等を使って、複数テーブルを結合させるようなSQLだったら、このrawQuery()の方がいいでしょう。

好き好きかもしれませんが、Androidアプリで使われる程度のSQLは難しいとは思えませんので、生のSQLを実行できるrawQuery()の方が、可読性もいいのではないかと思います。
あくまで個人的にはですけど。

ちなみに、rawQuery()はselect文専用です。
insert、update、delete等は、execSQL()メソッドを使います。
詳しくは下記をご覧下さい。
Androidアプリのデータ保存方法の一つ「SQLite」の使い方 行の追加・更新・削除編


スポンサーリンク




それでは、次はCursorインスタンスの基本的な使い方を見ていきましょう。

Cursorインスタンスの使い方

基本的には、取得したレコードを最初から最後までループで回して何かをする、という用法になると思います。
例えば以下のようなサンプルコードを見てください。


//query()またはrawQuery()の実行
Cursor c = -省略-;

if(c.moveToFirst()){
  do{
    long id = c.getLong(c.getColumnIndex(“_id”));
    String bookmark = c.getString(c.getColumnIndex(“bookmark”));
    System.out.println(id + “:” + bookmark);
  }while(c.moveToNext());
}


単純に取得した全レコードを標準出力で出力させているだけですが、上からみてみましょう。
まず、最初のif文ではCursor.moveToFirst()を実行していますね。
これは、取得した結果に対するカーソルを先頭に移動させる、という意味です。
成功したらtrueが返却されます。
その後の処理は、このmoveToFirst()が成功したら実行する、という事です。
ちなみに、取得したレコード件数が0件であった場合は、moveToFirst()の戻り値はfalseになります。

次は、後判定のループ処理となってますね。
Cursor.moveToNext()は、カーソルを次のレコードへ移動させる、という意味合いです。
このmoveToNext()の戻り値は、次のレコードがあればカーソルを移動させてtrueを戻します。
次のレコードが無ければfalseを返します。
ちなみに、後判定としているのは、一番最初のレコードの処理を行う為です。

レコードの内容を取り出す処理は、それぞれの列の型に合わせて、getLong()、getString()、getInt()等を使います。
引数は、カラムのインデックスで、要は何列目にあるのか?の数値です。
これは、列名を引数にして、getColumnIndex()で取得できます。

なんとも回りくどい仕様です・・・。
なぜ、引数に列名を指定しても取れるようにオーバーロードしてくれなかったの?と言いたいトコロです。
もちろん、インデックスがわかっていれば、メソッドを使わずにベタ書きでもいいですが、途中でテーブル定義を変えちゃっても正しく動作するように、今回のように実装しておいた方がいいのではないかなと思います。


JSPやサーブレットなどで、DBを使ったシステムの経験があれば難なく理解できるかと思います。
しかし、携帯組込みでは、データベースを取り扱うなんて今までは無かったかと思いますが、大体理解できましたでしょうか。