2012-11-09 17 views
48

come si può vedere nella documentazione la sintassi per fare inserto o aggiornamento è: INSERT OR REPLACE INTO <table> (<columns>) VALUES (<values>), la mia domanda è ci qualche funzione che unisce il seguente?SQLite Android Inserisci o Aggiorna

public long insert (String table, String nullColumnHack, ContentValues values) 
public int update (String table, ContentValues values, String whereClause, String[] whereArgs) 

oppure deve essere eseguito con un'istruzione SQL preparata e rawQuery?

Quali sono le migliori pratiche per inserire o aggiornare un aggiornamento in Android?

+2

Si potrebbe chiamare aggiornamento su una riga particolare .. Es. aggiorna ___ dove rowId = 4 .. e se l'aggiornamento restituisce 0 .. sai che non hai quella riga, quindi basta inserirla. – dymmeh

risposta

3

SQLiteDatabase.replace() è probabilmente quello che stai cercando. Non l'ho provato ma il doc dice che restituisce l'ID riga della riga appena inserita, quindi potrebbe funzionare.

41

questo è il tuo metodo SQLiteDatabase.insertWithOnConflict(). per capire cosa fa riferimento a su sqlite

+19

Questo metodo dovrebbe essere chiamato con il flag 'CONFLICT_REPLACE' per funzionare come dice la domanda. –

+0

Non dovrebbe essere l'updateWithOnConflict, quindi è possibile definire una clausola where? – NikkyD

+3

@NikkyD 'updateWithOnConflict' non inserirà una nuova riga se non esiste. Dove come 'insertWithOnConflict' funziona in questo modo: Se la riga esiste (conflitto), aggiornala, se no (nessun conflitto) inserisci una nuova. Quale penso sia la domanda. – kdehairy

71

Credo che tu stia chiedendo come INSERIRE nuove righe o AGGIORNA le righe esistenti in un solo passaggio. Mentre ciò è possibile in un singolo SQL raw come discusso in this answer, ho trovato che è più facile farlo in due passaggi in Android utilizzando SQLiteDatabase.insertWithOnConflict() utilizzando CONFLICT_IGNORE per conflictAlgorithm.

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 
} 

Questo esempio presuppone che la chiave tavola è apparecchiata per la colonna "_id", che si conosce il _id record e che c'è già riga 1 # (_ID = 1, Columna = "valoreA", ColumnB = "valoreB"). Qui è la differenza utilizzando insertWithOnConflict con CONFLICT_REPLACE e CONFLICT_IGNORE

  • CONFLICT_REPLACE sovrascrive valori esistenti in altre colonne null (es. ColumnB diventerà NULL e il risultato sarà _ID = 1, columna = "valueNEW", ColumnB = NULLO). Si perdono i dati esistenti come risultato e io non li uso nel mio codice.
  • CONFLICT_IGNORE salterà SQL INSERT per la riga 1 esistente e SQL AGGIORNA questa riga nel passaggio successivo, preservando il contenuto di tutte le altre colonne (ad esempio, il risultato sarà _id = 1, columnA = "valoreNEW", columnB = "valoreB").

Quando si tenta di inserire nuova riga # 2, che ancora non esiste, il codice verrà eseguito solo l'INSERT SQL nel insertWithOnConflict prima istruzione (cioè. Il risultato sarà _ID = 2, Columna = "valoreA" colonnaB = NULL).

Attenzione da this bug che causa il malfunzionamento di SQLiteDatabase.CONFLICT_IGNORE su API10 (e probabilmente su API11). La query restituisce 0 anziché -1 quando eseguo il test su Android 2.2.

Se non si conosce la chiave di registrazione _id o si ha una condizione che non creerà un conflitto, è possibile invertire la logica in UPDATE o INSERISCI. Ciò manterrà la chiave di record _id durante UPDATE o creerà un nuovo record _id durante INSERT.

int u = yourdb.update("yourtable", values, "anotherID=?", new String[]{"x"}); 
if (u == 0) { 
    yourdb.insertWithOnConflict("yourtable", null, values, SQLiteDatabase.CONFLICT_REPLACE); 
} 

L'esempio precedente presuppone che si desideri solo aggiornare il valore di data/ora nel record, ad esempio. Se si chiama insertWithOnConflict per primo, INSERT creerà un nuovo record _id a causa della differenza nella condizione di timestamp.

+0

Sarebbe più semplice utilizzare CONFLICT_REPLACE invece di CONFLICT_IGNORE, come altri hanno menzionato. – aleb

+4

@aleb - C'è un'enorme differenza tra CONFLICT_IGNORE e CONFLICT_REPLACE quando la query non specifica tutte le colonne nella tabella. Quando si utilizza CONFLICT_REPLACE, la query inserirà i valori NULL in tutte le colonne che non hanno alcun valore specificato nella variabile ContentValues. Nel mio caso, avevo bisogno di aggiornare solo una colonna su cinque senza conoscere il valore dei restanti quattro. L'utilizzo di CONFLICT_REPLACE ha forzato le altre quattro colonne per cancellare i valori. – theczechsensation

+0

ok, buono a sapersi, ma la domanda riguardava "INSERIRE O SOSTITUIRE" – aleb

4

È necessario identificare le colonne della tabella che la rendono UNICA una riga.

Esempio: _id, nome, lavoro, hours_worked

Le colonne sono nome e di lavoro, quando si identifica che utilizzare questo metodo:

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; 
} 

Nella classe:

public void insertOrUpdate(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)}); 
} 
+2

La domanda riguarda una funzione che unisce le funzioni di inserimento e aggiornamento, non su come usarle. – aleb

+0

@aleb questo mi ha aiutato molto. –

6

SQLiteDatabase.replace() fa questo, in pratica chiama:

insertWithOnConflict(table, nullColumnHack, initialValues, CONFLICT_REPLACE); 

Peccato che la documentazione non sia molto chiara.

2

Ho avuto lo stesso problema, ma ho capito che il mio oggetto ha già un ID che dovrebbe essere aggiornato e quando non ha un ID dovrebbe essere inserito quindi questo è passo passo cosa ho fatto per risolvere il problema:

1- nell'oggetto getId utilizzare Integer o inizializzare l'Es come si vede in forma: ecco il mio codice

public Integer getId() { 
    return id; 
} 

2- controllare l'ID nel metodo per l'inserimento o l'aggiornamento dopo aver messo tutto in ContentValues:

quello che succede qui è che io controllo per Id se esiste io aggiorno quella riga ma se il metodo di aggiornamento restituisce -1 significa che non c'erano righe con quell'ID quindi inserisco la riga, e se non ha un ID lo inserisco.

spero che questo aiuti.

0

cosa circa replaceOrThrow (tabella String, String nullColumnHack, contentValues ​​initialValues)

Documenti dicono ... Metodo pratico per la sostituzione di una riga nel database. Inserisce una nuova riga se una riga non esiste già.

Fondamentalmente si chiama insertWithOnConflict