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を使ったシステムの経験があれば難なく理解できるかと思います。
しかし、携帯組込みでは、データベースを取り扱うなんて今までは無かったかと思いますが、大体理解できましたでしょうか。
説明がとっても分かり易くて助かりました! ありがとうございます。
rowQuery –> rawQuery ですね!
スペルミスのご指摘、有難うございます。
全個所、「rawquery」へ修正しました。
また、「説明がわかりやすい」と仰って頂いてのご指摘、Mikeさんのお優しい人柄が伝わってきます。
本当にありがとうございました。
とてもわかりやすかったです。
WEBやってた人がandroidのSQLiteを使うとメソッドがいっぱいで。
何を使っていいか分からなかったので助かりました。
rawQuery()とexecSQL()だけでいけそうですね。
コメントありがとうございます。
そうですね。同感です。
Androidで使うSQLといえば、select、insert、delete、updateが出来れば充分だと思いますので、仰っている通り、rawQuery()とexecQuery()が使いこなせれば充分だと思います。
こんばんは
androidアプリを作成し始めた者です。
今までアプリは使うのみでだったのでアプリが実際どんな動作をしているのか分からず四苦八苦しています。
そこでネットで検索したらmucchinさんのブログに辿り着きました。
データの登録、保存と読み込みについてですが、やはり簡単なデータでもデータベースを利用したほうがいいのでしょうか?
あるいはテキストファイルでも十分機能するでしょうか?
仕事で使うアプリケーションはデータをテキストで保存し一覧表示させています。
すべて同じテキストファイルで保存するのではなく、日別でファイルが作成され、毎日違うファイルで保存されています。
アンドロイドアプリでもテキストでデータを扱うことは出来るでしょうか?
お時間がありましたらご教授お願いいたします。
vol canoさん
データベースでも、テキストファイルでも、使いやすい方法で良いと思います。
Androidでは、データベース以外にも、「プリファレンス」「ローカルファイル」という方法が使えます。
以下の記事を参考にしてください。
Androidアプリのデータ保存方法の一つ「プリファレンス」の使い方
Androidアプリのデータ保存方法の一つ「ローカルファイル」の使い方
お返事ありがとうございます。
下記サイト参考にさせていただきます。
画面表示、テキスト・ボタン・入力欄設置、画面遷移などで簡単な物は出来ますが、
やはりデータ登録、読み込み、入力された数値を用いて計算して表示するなど、
最低限この辺の動作が出来ないとアプリとして使い物にならないですよね。
しかしそんなこと素人には。。。
サンプルコード検索しながら少しずつ作っていきます。
また何かありましたら連絡いたします。
こんばんは
その後、色々試しまして、なんとかSQliteで情報登録、ListViewにDBの情報を表示する、リスト項目をクリックし確認画面で登録情報閲覧までできるようになりました。しかしその閲覧画面ですが、例えばtextview1に名前、textview2にmailを表示させようとすると、登録した数十件の名前・mailが一気にtextview1,2に表示されるというとんでもない状態になっています。それぞれ表示されてはいますが、どうもリストのどの項目を選択したのか確認が出来ていないようです(適当な解釈です)。edittextにも登録内容を表示させてみましたが、やはり状況は同じでした。get~positionみたいな物が関係しているのか分かりませんが、色々試しても全く問題解消しません。対処法はありませんでしょうか?
送る側の関係がありそうな箇所は以下のとおりです。
お時間がありましたらお願いします。
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id){
Intent intent = new Intent(xActivity.this, yActivity.class);
startActivity(intent);}
どの行を選択されたのか、という情報は次の画面に渡していますか?
コメントに書かれているソースを見る限りでは、何が選択されたのかを一切渡していないような…。
onItemClick()の引数の、positionかidかわかりませんが、どちらか利用出来ませんでしょうか。
もし、指摘誤りなら申し訳ありません。またご連絡下さい。
adminさん、お返事ありがとうございます。
その後、再度色々と試しまして無事問題が解決しました。
ただ今度は長押し・コンテキストメニューからの画面遷移・データ受け渡しが出来ない状況です。
一難去ってまた一難ですが、サンプルコード拾いながらがんばります。