現在、次のステートメントを使用して、Android デバイスの SQLite データベースにテーブルを作成しています。
CREATE TABLE IF NOT EXISTS 'locations' (
'_id' INTEGER PRIMARY KEY AUTOINCREMENT, 'name' TEXT,
'latitude' REAL, 'longitude' REAL,
UNIQUE ( 'latitude', 'longitude' )
ON CONFLICT REPLACE );
最後の conflict-clause により、同じ座標を持つ新しい挿入が行われたときに行が削除されます。SQLiteのドキュメントには、conflict-clause に関する詳細情報が含まれています。
代わりに、以前の行を保持し、それらの列を更新したいと思います。Android/SQLite 環境でこれを行う最も効率的な方法は何ですか?
CREATE TABLE
ステートメントの競合条項として。INSERT
トリガーとして。- メソッドの条件節として
ContentProvider#insert
。 - ...もっとよく考えることができます
データベース内でこのような競合を処理する方がパフォーマンスが高いと思います。また、挿入と更新のシナリオContentProvider#insert
を考慮してメソッドを書き直すのは難しいと思います。メソッドのコードは次のとおりです。insert
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long id = db.insert(DatabaseProperties.TABLE_NAME, null, values);
return ContentUris.withAppendedId(uri, id);
}
バックエンドからデータが到着したら、次のようにデータを挿入するだけです。
getContentResolver.insert(CustomContract.Locations.CONTENT_URI, contentValues);
ここに代替呼び出しを適用する方法を理解するのに問題がContentProvider#update
あります。さらに、これはとにかく私の好みのソリューションではありません。
編集:
@CommonsWare: を使用するというあなたの提案を実装しようとしましたINSERT OR REPLACE
。私はこの醜いコードを思いつきました。
private static long insertOrReplace(SQLiteDatabase db, ContentValues values, String tableName) {
final String COMMA_SPACE = ", ";
StringBuilder columnsBuilder = new StringBuilder();
StringBuilder placeholdersBuilder = new StringBuilder();
List<Object> pureValues = new ArrayList<Object>(values.size());
Iterator<Entry<String, Object>> iterator = values.valueSet().iterator();
while (iterator.hasNext()) {
Entry<String, Object> pair = iterator.next();
String column = pair.getKey();
columnsBuilder.append(column).append(COMMA_SPACE);
placeholdersBuilder.append("?").append(COMMA_SPACE);
Object value = pair.getValue();
pureValues.add(value);
}
final String columns = columnsBuilder.substring(0, columnsBuilder.length() - COMMA_SPACE.length());
final String placeholders = placeholderBuilder.substring(0, placeholdersBuilder.length() - COMMA_SPACE.length());
db.execSQL("INSERT OR REPLACE INTO " + tableName + "(" + columns + ") VALUES (" + placeholders + ")", pureValues.toArray());
// The last insert id retrieved here is not safe. Some other inserts can happen inbetween.
Cursor cursor = db.rawQuery("SELECT * from SQLITE_SEQUENCE;", null);
long lastId = INVALID_LAST_ID;
if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
lastId = cursor.getLong(cursor.getColumnIndex("seq"));
}
cursor.close();
return lastId;
}
ただし、SQLite データベースを確認すると、等しい列がまだ削除され、新しい ids で挿入されています。なぜこれが起こるのか理解できず、その理由は私の競合条項であると考えました. しかし、ドキュメントには反対のことが記載されています。
INSERT または UPDATE の OR 句で 指定されたアルゴリズムは、CREATE TABLE で指定されたアルゴリズムをオーバーライドします。アルゴリズムがどこにも指定されていない場合、ABORT アルゴリズムが使用されます。
この試行のもう 1 つの欠点は、insert ステートメントによって返される ID の値が失われることです。これを補うために、最終的にlast_insert_rowid
. dtmilano と swiz の投稿で説明されているとおりです。ただし、間に別の挿入が発生する可能性があるため、これが安全かどうかはわかりません。