幸福なプログラマ

プログラマは幸福になれる。

AndroidでSQLiteを使用する

データ定義


AndroidでSQLLiteを扱うにはSQLiteDatabaseクラスを使用します。
このSQLiteDatabaseインスタンス生成を簡略化してくれるのがSQLiteOpenHelperです。
SQLiteOpenHelperは抽象クラスであり、DBオープン時、テーブルのバージョンアップ時の実装を追加することができます。

public class MySQLiteOpenHelper extends SQLiteOpenHelper {

    public MySQLiteOpenHelper(Context context) {
        // 任意のデータベースファイル名と、バージョンを指定する
        super(context, "pastingcontroller.db", null, 1);
    }

    /**
     * このデータベースを初めて使用する時に実行される処理
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        // テーブルの作成、初期データの投入等を行う。
    }

    /**
     * アプリケーションの更新などによって、データベースのバージョンが上がった場合に実行される処理
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // データの退避、テーブルの再構成等を行う。
    }
}

コンストラクタで任意の名称のデータベースを作成します。
onCreateはこのヘルパクラスのインスタンスを使ってデータベースをオープンする際、コンストラクタで指定されたデータベースが無かった場合に実行されるメソッドです。
テーブルの作成や初期データの投入等を行います。
onUpgradeはこのヘルパクラスのインスタンスを使ってデータベースをオープンする際、バージョンがあがっていた場合に実行されるメソッドです。(ここで言うバージョンはコンストラクタの第四引数のことです。)
テーブルの更新や、それに伴うデータの退避・再投入を行います。

たとえば、onCreateでテーブルを作成する場合、以下のような実装になります。

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(
        "create table sample_table ("
        + "_id  integer primary key autoincrement not null, "
        + "text_column text not null, "
        + "num_column integer not null)" );
}

データ制御


データ操作を行うために、SQLiteDatabaseクラスのインスタンスを生成します。
作成したSQLiteOpenHelperの実装を用いて以下のようにインスタンスを生成します。

SQLiteOpenHelper sqliteOpenHelper = new MySQLiteOpenHelper(getApplicationContext());
SQLiteDatabase db = sqliteOpenHelper.getWritableDatabase();
try {
    // データ操作
} finally {
    db.close();
}

getWritableDatabaseは読み書き両用のインスタンスを生成するのに用います。
読み取り専用のインスタンスが必要な場合はgetReadableDatabaseを使用します。

トランザクション

SQLiteでも意図的に記述することでトランザクション制御が可能です。
ループで大量のInsert等を投げる場合はトランザクション制御を行ったほうが処理が早くなるようです。
参考:SQLiteでINSERTが激しく遅い件

// トランザクション開始
db.beginTransaction();
try {
    /** Insert等のDB操作 */
    
    db.setTransactionSuccessful();
} catch(Exception e) {
    e.printStackTrace();
}
finally {
    // トランザクション終了
    db.endTransaction();
}

beginTransactionトランザクションを開始し、endTransactionトランザクションを終了します。
トランザクション終了前にsetTransactionSuccessfulが呼ばれていればcommitされ、世ベレ帝無ければrollbackされます。なので、処理に成功した後は必ずsetTransactionSuccessfulを呼ぶ必要があります。

データ操作


登録

テーブルへのデータの登録(insert)は以下のように行います。

ContentValues values = new ContentValues();
values.put("text_column", "text");
values.put("num_column", 111);
try {
    db.insert("sample_table", null, values);
} finally {
    db.close();
}

登録に用いるデータははContentValuesオブジェクトに格納します。
insertの第一引数にテーブル名、第三引数に登録したいデータを渡します。
第二引数は少々複雑です。
全ての項目がnull許可のテーブルに対して、空のContentValuesオブジェクトを渡した場合、発行されるSQLは以下のようになると思われます。

INSERT INTO foo;

しかし、SQLiteでは以下のように最低でも1つのカラム名を明記しなければ登録することができません。

INSERT INTO foo (somecol) VALUES (NULL);

上記の仕様を満たすために、第二引数には第三引数が空のオブジェクトだった場合にinsert文に加えるカラム名を渡すことになります。
参考:Insert method of SQLiteDatabase

更新

データの更新(update)は以下のように行います。

ContentValues values = new ContentValues();
values.put("num_column", 222);

String whereClause = "text_column = ?";
String whereArgs[] = new String[1];
whereArgs[0] = "text";

try {
    db.update("sample_table", values, whereClause, whereArgs);
} finally {
    db.close();
}

第一引数がテーブル名、第二引数が更新対象のContentValuesオブジェクト、第三引数がwhere句に指定する条件、第四引数が条件の"?"にバインドする値になります。
第四引数のwhereArgsは文字列の配列です。数値型を条件にしたい場合は

String whereClause = "num_column = 111";

みたいな感じで直接条件文に記述することになります。
参考: Androidが再生産しているSQLインジェクション?

削除

データの削除(delete)は以下のようになります。

String whereClause = "text_column = ?";
String whereArgs[] = new String[1];
whereArgs[0] = "text";

try {
    db.delete("sample_table", whereClause, whereArgs);
} finally {
    db.close();
}

読み取り

データの読み取り(select)は以下のようになります。

String[] columns = {"text_column ", "num_column"};
String selection = "text_column = ?";
String[] selectionArgs = {"text"};
String groupBy = null;
String having = null;
String orderBy = null;
try {
    Cursor cursor = db.query("sample_table", columns, selection, selectionArgs, groupBy, having, orderBy);
    StringBuilder text = new StringBuilder();
    while (cursor.moveToNext()){
        String textColumn = cursor.getString(0);
        int numColumn = cursor.getInt(1);
    }
} finally {
    db.close();
}

第一引数にテーブル名、第二引数に検索対象のカラム名(nullを指定すると全てが対象になります)、第三引数に検索条件、第四引数に検索条件へのバインド値を指定します。
必要に応じてgroup by句、having句、order by句を指定します。