Подтвердить что ты не робот

Вставка или обновление 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?

4b9b3361

Ответ 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 из-за разницы в состоянии отметки времени.

Ответ 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