Вставка или обновление Android SQLite
как можно видеть в документации, синтаксис для вставки или обновления: INSERT OR REPLACE INTO <table> (<columns>) VALUES (<values>)
, в моем вопросе есть какая-либо функция, которая объединяет следующее?
public long insert (String table, String nullColumnHack, ContentValues values)
public int update (String table, ContentValues values, String whereClause, String[] whereArgs)
или это нужно сделать с помощью подготовленного оператора SQL и rawQuery?
Какие лучшие практики для вставки или обновления в Android?
Ответы
Ответ 1
Я полагаю, что вы спрашиваете, как ВСТАВИТЬ новые строки или ОБНОВИТЬ существующие строки за один шаг. Хотя это возможно в одном необработанном 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 перезапишет существующие значения в других столбцах в нулевое значение (т.е. ColumnB станет NULL, а результатом будет _id = 1, columnA = "valueNEW", columnB = NULL). В результате вы потеряете существующие данные, а я не использую их в своем коде.
- CONFLICT_IGNORE пропустит SQL INSERT для вашей существующей строки # 1, и вы ОБНОВИТЕ эту строку SQL на следующем шаге, сохранив содержимое всех других столбцов (т.е. результатом будет _id = 1, columnA = "valueNEW", columnB = " VALUE млрд ").
При попытке вставить новую строку № 2, которая еще не существует, код будет выполнять SQL INSERT только в первом операторе insertWithOnConflict (т.е. результатом будет _id = 2, columnA = "valueNEW", columnB = NULL).
Остерегайтесь этой ошибки, которая вызывает сбои SQLiteDatabase.CONFLICT_IGNORE в API10 (и, вероятно, API11). Запрос возвращает 0 вместо -1 при тестировании на Android 2.2.
Если вы не знаете ключ записи _id или у вас есть условие, которое не создает конфликт, вы можете изменить логику на UPDATE или INSERT. Это сохранит ваш ключ записи _id во время UPDATE или создаст новую запись _id во время INSERT.
int u = yourdb.update("yourtable", values, "anotherID=?", new String[]{"x"});
if (u == 0) {
yourdb.insertWithOnConflict("yourtable", null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
В приведенном выше примере предполагается, что вы просто хотите обновить значение метки времени в записи, например. Если вы сначала вызовите insertWithOnConflict, INSERT создаст новую запись _id из-за разницы в состоянии отметки времени.
Ответ 2
это ваш метод SQLiteDatabase.insertWithOnConflict(). чтобы понять, что это значит, этот документ на sqlite
Ответ 3
SQLiteDatabase.replace() делает это, в основном вызывает:
insertWithOnConflict(table, nullColumnHack, initialValues, CONFLICT_REPLACE);
Слишком плохо, что документация не очень ясна.
Ответ 4
Имя операции для этого - "upsert", и как я ее решаю, идентифицирую столбцы вашей таблицы, которые делают строку УНИКАЛЬНОЙ.
Пример:
_id, name, job, hours_worked
Столбцы, которые мы будем использовать, - это имя и работа.
private int getID(String name, String job){
Cursor c = dbr.query(TABLE_NAME,new String[]{"_id"} "name =? AND job=?",new String[]{name,job},null,null,null,null);
if (c.moveToFirst()) //if the row exist then return the id
return c.getInt(c.getColumnIndex("_id"));
return -1;
}
В вашем классе менеджера баз данных:
public void upsert(String name, String job){
ContentValues values = new ContentValues();
values.put("NAME",name);
values.put("JOB",job);
int id = getID(name,job);
if(id==-1)
db.insert(TABLE_NAME, null, values);
else
db.update(TABLE_NAME, values, "_id=?", new String[]{Integer.toString(id)});
}
Ответ 5
SQLiteDatabase.replace() - это, вероятно, то, что вы ищете. Я не пробовал, но документ говорит, что он возвращает идентификатор строки недавно вставленной строки, поэтому он может работать.
Ответ 6
У меня была такая же проблема, но я понял, что когда у моего объекта уже есть идентификатор, он должен быть обновлен, а когда он не имеет идентификатор, он должен быть вставлен так, что это шаг за шагом, что я сделал, чтобы решить проблему:/p >
1- в вашем объекте getId используйте Integer или инициализируйте Id, как вы сочтете нужным: вот мой код
public Integer getId() {
return id;
}
2- проверьте идентификатор в вашем методе для вставки или обновления после того, как вы поместите все в ContentValues:
if(myObject.getId()!= null ){
int count = db.update(TABLE_NAME,myContentValues,ID + " = ? ",
new String[]{String.valueOf(myObject.getId())});
if(count<=0){
//inserting content values to db
db.insert(TABLE_NAME, null, myContentValues);
}
} else {
db.insert(TABLE_NAME, null, myContentValues);
}
что происходит здесь, так это то, что я проверяю Id, если существует. Я обновляю эту строку, но если метод обновления возвращает -1, это означает, что не было строк с этим идентификатором, поэтому я вставляю строку, и если у нее нет идентификатора я вставьте его.
надеюсь, что это поможет.
Ответ 7
Что о
replaceOrThrow (Строковая таблица, String nullColumnHack, ContentValues initialValues)
Документы говорят... Удобный метод для замены строки в базе данных.
Вставляет новую строку, если строка еще не существует.
В основном это вызывает insertWithOnConflict