Using insertWithOnConflict for update or insert - android

I need to insert or update and I found the method insertWithOnConflict of the SQLiteDatabase, but I do not know how it checks if the entry already exists.
Theoretically I need a "Where" argument to check if a certain ID exists, and if so, it should replace all other columns.
This is what I have now, but I donĀ“t think that the second argument is the unique id
ContentValues args = new ContentValues();
args.put(AppDatabase.COLUMN_ID, entry.getId());
args.put(AppDatabase.COLUMN_NAME, entry.getAppname());
args.put(AppDatabase.COLUMN_URL, entry.getAppUrl());
database.insertWithOnConflict(AppDatabase.TABLE_FILELIST, COLUMN_ID, args, SQLiteDatabase.CONFLICT_REPLACE);
How can I manage this behaviour?

Make sure you have some appropriate constraint in your table, such as PRIMARY KEY or UNIQUE.
When inserting, add a value to this constrained column via ContentValues. If inserting the new row would violate some constraint, the conflicting rows are first deleted and then the new row is inserted.
In your case, COLUMN_ID looks like a good candidate for PRIMARY KEY constraint. The second arg nullColumnHack with value COLUMN_ID in your code is not necessary, you can pass it as null.

Related

how can we get the id of a row that we insert through code

I need to retrieve the id of the row inserted just now. ie, i have a table for words and a table for meaning. i need the wordId of the word i insert in the table for words and that wordId is used for inserting the meaning in meaning table. Can anyone help me out??
I thought i could use trigger and tried the trigger:
"CREATE TRIGGER IF NOT EXISTS word_insert_trigger AFTER INSERT ON tb_words BEGIN select NEW.word_id from tb_words; END;"
like this. i tried this in sqlite dbbrowser. but it didn't work out.
i need the row id when i insert a row like this :"insert into tb_words(word_name) values('test');"
How can i do that without using "SELECT last_insert_rowid()"? like in the following link:
How to retrieve the last autoincremented ID from a SQLite table?
No need for a trigger. Use the SQliteDatabase insert method. It returns the id (as a long) (more correctly it returns the rowid and assuming that the word_id column has been defined as an alias of the rowid column, then the returned value will be the value assigned to the word_id column).
An alias of the rowid column is defined if word_id INTEGER PRIMARY KEY is coded (the AUTOINCREMENT key may be used BUT in generally should not be used).
You may wish to read SQLite AUTOINCREMENT and/or Rowid Tables
Instead of something like :-
db.execsql("insert into tb_words(word_name) values('test');");
You would use something like :-
ContentValues cv = new ContentValues();
cv.put("word_name","test");
long word_id = db.insert("tb_words",null,cv);

SQLite Autoincrement not inserting

I have an SQLite Database and when I insert the ID should be automaticly incrementet with AUTOINCREMENT.
But it is always null.
This is the create table
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE ausgaben (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, TAG text,DATUM text, AUSGABE text, MENGE text, KATEGORIE text)");
}
And this is how I insert data:
public boolean insertAusgabe(String tag, String datum, String ausgabe, String menge, String kategorie){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.putNull("id");
contentValues.put(AUSGABEN_TAG,tag);
contentValues.put(AUSGABEN_DATUM,datum);
contentValues.put(AUSGABEN_AUSGABE,ausgabe);
contentValues.put(AUSGABEN_MENGE,menge);
contentValues.put(AUSGABEN_KATEGORIE,kategorie);
db.insert(TABLE_NAME,null,contentValues);
return true;
}
If I understand right, this should work correctly.
But the database looks like this:
It would appear that you are expecting the id column to be null rather than a number.
If you code id INTEGER PRIMARY KEY NOT NULL AUTOINCREMENT (see note about AUTOINCREMENT below) then that column is a special column that is an alias of the rowid column (unless the table has been defined using WITHOUT ROWID).
The rowid column cannot be null and must be a integer value. If an attempt is made to insert a row where the value for the column is null (or not specified) then SQLite will assign an integer value (long for java). 1 if there are no rows in the table then 1 greater than the highest number used.
Hence why you have a sequence of numbers in the id column.
If, for example the table were defined using id INT PRIMARY KEY NOT NULL then, the id column IS NOT an alias of the rowid column. (AUTOINCREMENT can then not be used as it can only be used for an alias of the rowid column) Then none of the inserts would work as the value for the id column would be NULL which due to the coding of the NOT NULL constraint will result in a constraint conflict.
However if the column were defined using id INT PRIMARY KEY, then null values for the id would be allowed. Noting that coding PRIMARY KEY, implies a UNIQUE constraint, that is all values must be UNIQUE. SQLite considers all NULL values as being unique in comparison to each other.
So the last definition would allow what appears to be your expected result. However, what use would an indeterminate value be for the purpose of identifiyting a row? (that's rhetorical).
As such the result you initially obtained, is the more useful result. Even if not intended.
A note on AUTOINCREMENT
AUTOINCREMENT is very likely not needed, this specifies an extension of the rowid determination algorithm in that it
enforces the latest rowid value being greater than any existing or used rowid,
that is it relies upon another table, namely sqlite_sequence to record the highest allocated rowid and then it uses the higher of the highest existing rowid or the value stored for the table in the sqlite_sequence table.
With AUTOINCREMENT when the highest possible value (9223372036854775807) has been assigned and an attempt is made to insert a new row. Then an SQLITE_FULL error will result. Without, attempts are made to use an random unused value (e.g. if rows have been deleted).
With AUTOINCREMENT there is an overhead (something like 8-12% according to What are the overheads of using AUTOINCREMENT for SQLite on Android?).
NOTE
It should be noted that there is no gaurantee that the rowid, with or without the AUTOINCREMENT keyword will increase by 1. There are some situations where values may be skipped as per
Note that "monotonically increasing" does not imply that the ROWID always increases by exactly one. One is the usual increment. However, if an insert fails due to (for example) a uniqueness constraint, the ROWID of the failed insertion attempt might not be reused on subsequent inserts, resulting in gaps in the ROWID sequence. AUTOINCREMENT guarantees that automatically chosen ROWIDs will be increasing but not that they will be sequential.
SQLite Autoincrement
*In short it is not wise to have any expectation of the * id/rowid column to be anything other than a means of efficiently identifying a row.

Update/replace row if same ID already exists

I have the below method which inserts values in my sqlite db. I'm trying to update the code to handle situations where "carid" and "sellerno" already exist in the table and if they do to replace with the new values being inserted. Any help is appreciated.
public void addListItem(String carid,String sellerno,String condition,String dat) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(carid, carid);
values.put(sellerno, sellerno);
values.put(cond, condition);
values.put(updatetime, dat);
db.insert(TABLE_CARS, null, values);
db.close();
}
There are two requirements:
SQLite needs to know that the combination of carid and sellerno must be unique for all rows in the table.
SQLite needs to know what to do when an insert or update results in a conflict (more than one row with the same combination of values for those columns).
You can do both of these at once by modifying your CREATE TABLE command as follows:
CREATE TABLE tableName (
column1 ...,
column2 ...,
...,
UNIQUE(column1, column2) ON CONFLICT REPLACE)
Now any insert/update will automatically replace the values in existing rows when the insert/update would create a conflict.
However, there may be situations where you do NOT want to replace the values in the row when there is a conflict. In those cases, you should specify the conflict algorithm in the insert/update itself (using this or this), which will override the replace algorithm specified above. Alternatively, you can leave off the ON CONFLICT REPLACE above and just use regular inserts/updates, but then you must insert/update with conflict when you want to replace.
You can read more about conflict algorithms here.
The update code is very similar to what you have now.
You have to add the new values but the same ids that you want, and then instead of the method insert(...) you use replace(...) or update(...).
db.update(TABLE_CARS, values, "_id "+"="+1, null);
// The third argument above is the where clause.
The other way would be:
db.replace(TABLE_CARS, null, values);
The rest of your code is the same. Just change the insert line.

Column columnname is not unique(code 19)

this is the code where I am trying to insert into my table and getting an exception that column ShopName(COL_SN) is not unique though I am giving a name that is not already existing in the database.That particular column is the primary key of the table
public void insert(String sn,String skn,String sa,String un,String pwd) throws SQLiteConstraintException
{
sdb=this.getWritableDatabase();
System.out.println("in insert method");
//sdb.execSQL("insert into " + TABLE_ShopDetails + " values(" +sn+ "," +skn+ "," +sa+ "," +un+ "," +pwd+ ")");
ContentValues cv=new ContentValues();
cv.put(COL_SN,sn);
cv.put(COL_SKN,skn);
cv.put(COL_SA,sa);
cv.put(COL_UN,un);
cv.put(COL_PWD,pwd);
sdb.insert(TABLE_ShopDetails,COL_SN,cv);
sdb.insert(TABLE_ShopDetails,COL_SKN,cv);
sdb.insert(TABLE_ShopDetails,COL_SA,cv);
sdb.insert(TABLE_ShopDetails,COL_UN,cv);
sdb.insert(TABLE_ShopDetails,COL_PWD,cv);
}
just call insert only once
sdb.insert(TABLE_ShopDetails,null,cv);
You should call insert() only once.
The ContentValues object already contains the values for all columns. By inserting multiple times, you're trying to create duplicate records, which results in a primary key violation.
The second parameter can be null, it's only for special cases (when values is empty).
You definitely only need to call insert once as others have said. The second optional parameter should most likely be null, it is for the following ...
optional; may be null. SQL doesn't allow inserting a completely empty row without naming at least one column name. If your provided values is empty, no column names are known and an empty row can't be inserted. If not set to null, the nullColumnHack parameter provides the name of nullable column name to explicitly insert a NULL into in the case where your values is empty.
Also you might want to look into setting up a content provider. The link below would serve as a great tutorial.
Android SQLite database and content provider - Tutorial

Android Sqlite INSERT error when table contains only _id

I have a SQLite table that contains only the _id:
"create table rule (_id integer primary key);";
When running this set of commands:
ContentValues initialValues = new ContentValues();
mDb.insert(TABLE, null, initialValues)
I obtain the following exception:
android.database.sqlite.SQLiteException: near "null": syntax error (code 1): , while compiling: INSERT INTO rule(null) VALUES (NULL)
The initial error occurs because ContentValues cannot be empty. Android provides a convenience parameter called nullColumnHack that allows you to pass a single column with the value null, to bypass this problem.
However this doesn't apply in my case because the row id (_id) cannot be null! Based on the syntax found in the SQLite language docs, I would like to be able to run the SQLite code:
INSERT INTO rule DEFAULT VALUES;
How can i achieve something like this using the android insert method? Or is there something I need to add to my create statement?
UPDATE: In the situation where a table contains ONLY a rowid, the proper syntax is to use INSERT INTO __ DEFAULT VALUES.
The sqlite insert method listed in android does not support DEFAULT VALUES as an option.
A bug has been filed with google and to get support for default values the following commands would need to be executed:
mDb.execSQL("INSERT INTO rule DEFAULT VALUES;");
Cursor c = mDb.rawQuery("SELECT last_insert_rowid()",null);
c.moveToFirst();
int rowid = c.getInt(0);
As stated in the accepted answer, we can get around this (and DEFAULT VALUES) by using nullHackColumn and assigning the row id (_id) to null and letting SQLite make the conversion from null to the auto-incremented value.
As jeet mentioned you can provide nullColumnHack as a second parameter. And as you yourself mentioned autoincrement isn't necessary to increment a value of primary key.
So the syntax:
insert into rule (_id) values(null)
where _id is primary key and autoincremented value is correct for sql. I think most SQL databases will replace null with new incremented value, at least MySQL, SQLite and Oracle can do this
Thus:
ContentValues cv = new ContentValues();
db.insert("rule", "_id", cv);
should give you desired results.
You need to add autoincrement to your create table query like:
"create table rule (_id integer primary key autoincrement);";
In your case you need to manually set the ID of the row with each insert. this way it will increment it automatically when you insert an empty row as you did in your case.
Try this way :
ContentValues initialValues= new ContentValues();
if(check here --id is null----)
{
initialValues.put("_id", "0");
}
else
{
initialValues.put("_id", id);
}
mDb.insert(TABLE, null, initialValues)
Check following:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert(java.lang.String, java.lang.String, android.content.ContentValues)
SQL doesn't allow inserting a completely empty row without naming at least one column name. If your provided values is empty, no column names are known and an empty row can't be inserted. If not set to null, the nullColumnHack parameter provides the name of nullable column name to explicitly insert a NULL into in the case where your values is empty.
the insert needs a null value you just have to put
db.insert ("people", null, c);

Categories

Resources