LoginSignup
24

More than 5 years have passed since last update.

Android のデータベースでテーブルの結合に困ること

Last updated at Posted at 2014-05-12

Android で利用できるデータベースは SQLite3 ですが、クエリの結果はCursorという抽象化されたインタフェースで取り扱っています。
SQLiteDatabase で直接 SQL を実行するインタフェースもありますが、SELECT 文だけは特別扱いされ、返り値がCursorとなるため、ほぼ確実にクエリ結果を取り扱うにはCursorとつきあうことになります。

ここで、あるデータベースに以下のような複数のテーブルがあったと仮定します。

  • table_1
_id name description
1 foo first entry
2 bar second entry
3 baz another entry
  • table_2
_id age description
1 13 hogehoge
2 14 fugafuga
3 16 piyopiyo

これらのテーブルから、_idを元に結合したクエリを投げてみます。


SELECT * FROM table_1, table_2 WHERE table_1._id = table_2._id;

これによって得られるCursorで、クエリ結果のセットにアクセスするには、以下のようにします。


Cursor cursor = // query...

if (cursor == null) 
    return;

try {
    while (cursor.moveToNext()) {
        long id = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
        String name = cursor.getString(cursor.getColumnIndex("name"));
        int age = cursor.getInt(cursor.getColumnIndex("age"));
        String description = cursor.getString(cursor.getColumnIndex("description"));

        // do something with the result...
    }
} finally {
    cursor.close();
}

Cursor#getColumnIndex(String)を使って、カラム名に対応する、1行分のデータを格納しているコレクションのインデックスを取得し、そのインデックスを元に、結果セットからデータを取り出します。

さて、table_1table_2にはそれぞれ、descriptionという名前のカラムが存在します。
Cursorを経由したアクセスでは、どちらのものかを区別するようなコードの書き方はしていませんが、結果自体は取得できているようです。

実のところ、テーブルを結合した際、同じ名前のカラムが存在した時、それぞれテーブルごとにカラムを絞り込む機能はCursorにはありません。
内部的には、Mapのようなデータ構造でクエリ結果のセットを管理しています。つまり、カラム名の衝突はMapにおけるキーの衝突と同じ結果をもたらすことになります。よって、データ自体は存在し取得もできていますが、取得できるデータは、Cursorが持つ結果セットに最後に追加された(実質上書きされた)データになります。

このような事態を避けるには、カラム名を衝突しないように作るか、ある程度正規化しないで、最初から結合した状態にしておくか、クエリを別々に分けるかのいずれかの手段で対処します。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24