目前,我正在使用以下语句在 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 );
最后的冲突子句导致在完成具有相同坐标的新插入时删除行。SQLite 文档包含有关冲突子句的更多信息。
相反,我想保留以前的行并只更新它们的列。在 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 算法。
这种尝试的另一个缺点是您丢失了插入语句返回的 id 的值。为了弥补这一点,我终于找到了一个选项来要求last_insert_rowid
. 正如dtmilano 和 swiz 的帖子中所解释的那样。但是,我不确定这是否安全,因为中间可能会发生另一个插入。