新しい行を挿入する方法または既存の行を更新する方法をお尋ねだと思います ワンステップで。この回答で説明されているように、これは単一の生のSQLで可能ですが、AndroidでSQLiteDatabase.insertWithOnConflict()を使用してconflictAlgorithmにCONFLICT_IGNOREを使用すると、2つのステップでこれを行う方が簡単であることがわかりました。
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 ="valueB")。
まだ存在しない新しい行#2を挿入しようとすると、コードは最初のステートメントinsertWithOnConflictでSQL INSERTのみを実行します(つまり、結果は_id =2、columnA ="valueNEW"、columnB =NULLになります)。
SQLiteDatabase.CONFLICT_IGNOREがAPI10(およびおそらくAPI11)で誤動作する原因となるこのバグに注意してください。 Android 2.2でテストすると、クエリは-1ではなく0を返します。
レコードキー_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を作成します。