我相信您在问如何一步插入新行或更新现有行。虽然这在这个答案中讨论的单个原始 SQL 中是可能的,但我发现在 Android 中使用SQLiteDatabase.insertWithOnConflict()使用 CONFLICT_IGNORE 进行冲突算法更容易做到这一点。
ContentValues initialValues = new ContentValues();
initialValues.put("_id", 1); // the execution is different if _id is 2
initialValues.put("columnA", "valueNEW");
int id = (int) yourdb.insertWithOnConflict("your_table", null, initialValues, SQLiteDatabase.CONFLICT_IGNORE);
if (id == -1) {
yourdb.update("your_table", initialValues, "_id=?", new String[] {"1"}); // number 1 is the _id here, update to variable for your code
}
此示例假定为列“_id”设置了表键,您知道记录 _id,并且已经存在第 1 行(_id=1,columnA = “valueA”,columnB = “valueB”)。这是使用 insertWithOnConflict 与 CONFLICT_REPLACE 和 CONFLICT_IGNORE 的区别
- CONFLICT_REPLACE 会将其他列中的现有值覆盖为 null(即 columnB 将变为 NULL,结果将是 _id=1,columnA = "valueNEW",columnB = NULL)。结果你丢失了现有数据,我没有在我的代码中使用它。
- CONFLICT_IGNORE 将跳过现有行#1 的 SQL INSERT,您将在下一步中 SQL UPDATE 此行,保留所有其他列的内容(即结果将是 _id=1,columnA = "valueNEW",columnB = "值 B")。
当您尝试插入尚不存在的新行 #2 时,代码将仅在第一条语句 insertWithOnConflict 中执行 SQL INSERT(即结果将是 _id=2,columnA = "valueNEW",columnB = NULL)。
请注意这个导致 SQLiteDatabase.CONFLICT_IGNORE 在 API10(可能还有 API11)上发生故障的错误。当我在 Android 2.2 上测试时,查询返回 0 而不是 -1。
如果您不知道记录键 _id 或者您有一个不会产生冲突的条件,您可以将逻辑反转为 UPDATE 或 INSERT。这将在 UPDATE 期间保留您的记录密钥 _id 或在 INSERT 期间创建新记录 _id。
int u = yourdb.update("yourtable", values, "anotherID=?", new String[]{"x"});
if (u == 0) {
yourdb.insertWithOnConflict("yourtable", null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
上面的示例假设您只想更新记录中的时间戳值。如果先调用insertWithOnConflict,由于时间戳条件的不同,INSERT会创建新的记录_id。