Insert or Replace Multiple Row with where condition in SQLite Query - android

I need a single SQLite query to insert or update in SQLite table.
MyTable:
Id(Primary key and not null)
Name
PhoneNumber
Expected Query: If the Id is not present then have to insert a new row
and If the existing row value is changed then update the row when inserting multiple row.
EDIT 1:
I have posted INSERT query i have tried in Insert Multiple Rows in SQLite Error (error code = 1). Like that i I have tried using "INSERT OR REPLACE". But it is working with Firfox SQLite Manager Not working with Android SQLite.
I have used sDataBase.execSQL(query) to execute this query.

Try this:
String sql = "INSERT OR REPLACE INTO MyTable (Name, PhoneNumber) VALUES (?,?)";
SQLiteStatement st = db.compileStatement(sql);
And write or update:
public void writeOrUpdateData(ArrayList<MyClass> data) {
try {
db.beginTransaction();
for(int i = 0; i < data.size(); i++) {
st.clearBindings();
st.bindLong(1, data.get(i).getName());
st.bindString(2, data.get(i).getPhoneNumber);
st.executeInsert();
}
db.setTransactionSuccessful();
}
catch(Exception e) {}
finally {
db.endTransaction();
}
}
This way you get bulk insert/update, which is quite efficient!

I have created database with primary key only in Firefox SQLite Manager. I have missed this in SQLite database in Android. Now i have created database with PRIMARY KEY and NOT NULL. Now Working fine.

Related

deleting one duplicate row in sqlite

I wish to just delete one duplicate row in here (For example, Jim 21)
SQLiteDatabase myDataBase=this.openOrCreateDatabase("Users",MODE_PRIVATE,null);
myDataBase.execSQL("CREATE TABLE IF NOT EXISTS users (name VARCHAR,age INT(3))");
myDataBase.execSQL("INSERT INTO users(name,age) VALUES ('Rob', 34)");
myDataBase.execSQL("INSERT INTO users(name,age) VALUES ('Nat', 22)");
myDataBase.execSQL("INSERT INTO users(name,age) VALUES ('Jim', 21)");
myDataBase.execSQL("DELETE FROM users WHERE name='Jim'");
Cursor c=myDataBase.rawQuery(" SELECT * FROM users", null);
int nameIndex=c.getColumnIndex("name");
int ageIndex=c.getColumnIndex("age");
c.moveToFirst();
while (c!=null){
Log.i("name",c.getString(nameIndex));
Log.i("age",Integer.toString(c.getInt(ageIndex)));
c.moveToNext();
}
I have tried this
myDataBase.execSQL("DELETE FROM users WHERE name='Jim' LIMIT 1");
But it is throwing a syntax error. I know LIMIT is not syntactically allowed in android. So how do I just delete one record of Jim when there are duplicates?
Thank you.
Limit will not work with Delete query,it's only for Select number of record
Update the query
myDataBase.execSQL("DELETE FROM users WHERE name='Jim'");
you can add more condition for remove specific records
myDataBase.execSQL("DELETE FROM users WHERE name='Jim' AND age=21 ");
There are several ways to achieve this. However, I would suggest to put a unique constraint on your name field.
myDataBase.execSQL("CREATE TABLE IF NOT EXISTS users (name text unique not null, age INT(3))");
Now for creating new entries in your users table, get a function like the following.
public void createUser(List<User> userList) {
if (userList != null && !userList.isEmpty()) {
SQLiteDatabase db = this.openOrCreateDatabase("Users",MODE_PRIVATE,null);
db.beginTransaction();
try {
for (User user : userList) {
ContentValues values = new ContentValues();
values.put("name", user.getName());
values.put("age", user.getAge());
// Replace on conflict with the unique constraint
db.insertWithOnConflict("users", null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
} catch (Exception e) {
e.printStackTrace();
}
db.setTransactionSuccessful();
db.endTransaction();
}
}
In this way, you do not have to delete any duplicate rows in your table as there will be no duplicate rows either.
However, if your implementation needs duplicate rows and then deleting only the first when you are trying to delete based on some condition then you might consider using the sqlite built-in column ROWID. You get all the rows that matches your condition and save the ROWID of them all. Then you delete the row that matches the ROWID you want to delete.
delete from users where ROWID = 9
Here's the developers documentation of using ROWID.
The approach I would take is to create a table where the duplicates are automatically resolved when data is inserted. Make the "name" field a primary key. Here's the CREATE statement:
CREATE TABLE users (name TEXT PRIMARY KEY ON CONFLICT IGNORE,age INTEGER);
"ON CONFLICT IGNORE" will always keep the first "name" record in the database. If you want to always keep the last record inserted, use "ON CONFLICT REPLACE". For example:
INSERT INTO users VALUES ('Jim','21');
INSERT INTO users VALUES ('Jim','23');
INSERT INTO users VALUES ('Jim','43');
If you use "ON CONFLICT IGNORE" Then "SELECT * FROM users" would produce "Jim|21". If you use "ON CONFLICT REPLACE" Then "SELECT * FROM users" would produce "Jim|43".

How to bind values to SQLiteStatement for insert query?

Insertion code using SQLiteStatement usually looks like this,
String sql = "INSERT INTO table_name (column_1, column_2, column_3) VALUES (?, ?, ?)";
SQLiteStatement statement = db.compileStatement(sql);
int intValue = 57;
String stringValue1 = "hello";
String stringValue2 = "world";
// corresponding to each question mark in the query
statement.bindLong(1, intValue);
statement.bindString(2, stringValue1);
statement.bindString(3, stringValue2);
long rowId = statement.executeInsert();
Now this works perfectly fine but the issue I find here is that I have to be very careful about binding correct data to corresponding indexes. A simple swap of index will give me an error.
Also let's say in future my column_2 gets dropped from the table, then I would have to change all the indexes after the column_2 index otherwise the statement won't work. This seems trivial if I just have 3 columns. Imagine if a table has 10-12 (or even more) columns and column 2 gets dropped. I'll have to update the index of all the subsequent columns. This whole process seems inefficient and error prone.
Is there an elegant way to handle all this?
Edit : Why would I want to use SQLiteStatement ? Check this :Improve INSERT-per-second performance of SQLite?
Insertions can be done with ContentValues:
ContentValues cv = new ContentValues();
cv.put("column_1", 57);
cv.put("column_2", "hello");
cv.put("column_3", "world");
long rowId = db.insertOrThrow("table_name", null, cv);
But in the general case, the most correct way would be to use named parameters. However, these are not supported by the Android database API.
If you really want to use SQLiteStatement, write your own helper function that constructs it from a list of columns and takes care of matching it with the actual data. You also could write your own bindXxx() wrapper that maps previously-saved column names to parameter indexes.
You can use ContentValues with beginTransaction into SQLite that is quite easy as well as faster then prepared statements
For this you have to create ContentValues Array previously or create Content values object into your loop. and pass into insert method .this solution solve your both of problem in one.
mDatabase.beginTransaction();
try {
for (ContentValues cv : values) {
long rowID = mDatabase.insert(table, " ", cv);
if (rowID <= 0) {
throw new SQLException("Failed to insert row into ");
}
}
mDatabase.setTransactionSuccessful();
count = values.length;
} finally {
mDatabase.endTransaction();
}

Bulk Update Database

I've been looking on this site for a while but have not found the answer. I am trying to do a bulk update on data that I know is already in the table. I have one column that needs to be set when a certain condition comes back for the row ID. Here is the single method but I want to make this more efficient and do it as a bulk. Our database is not in a Provider so I just using a Helper class.
public void markUnavailable(int myId) {
SQLiteDatabase db = this.getWritableDatabase();
String sql = "UPDATE " + MYTABLE + " SET " + Col.IS_AVAILABLE + "= 0"+ " WHERE " + Col.MY_ID + "=" + myId;
db.execSQL(sql);
db.close();
}
I would like to pass in an array of myIds to do the bulk Update. I can't do a Insert or Replace statement because I don't have access to all the column data and don't want to pass this through due to too many codes changes.
public void markUnavailable(int[] myId) {
// ????
/// need some way to loop through and update in bulk
}
Try UPDATE tablename SET column=0 WHERE ID IN (...), where ... is a comma-delimited list of ID values.
I'm not an Android developer, but according to good database practices, you should:
public void markUnavailable(int[] myId) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
SQLiteStatement upd=db.compileStatement("UPDATE "+MYTABLE+" SET "+Col.IS_AVAILABLE+"=0 WHERE "+Col.MY_ID+"=?";
for (int i = 0; i < myId.length; i++) {
upd.bindLong(1, myId[i]);
upd.execute();
}
db.endTransaction();
}
Android has SQLiteDatabase.update would be very usefull in this case, but String [] whereArgs would not deal well with your int[] myId.
The fastest way to do a bulk update would be to do it as a single transaction,by using begin and end transactions. Also if the size of the database is large it will be a good idea to make myID as the primary key of the table as it will significantly increase the speed of the speed in fetching the rows for update when the WHERE clause is used.[It is said that indexing can reduce the speed of update and insert but when the where clause is used,indexing has always increased my speed by huge margins.
public void markUnavailable(int[] myId) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
SQLiteStatement upd=db.compileStatement("UPDATE "+MYTABLE+" SET "+Col.IS_AVAILABLE+"=0 WHERE "+Col.MY_ID+"=?");
for (int i = 0; i < myId.length; i++) {
upd.clearBindings();
upd.bindLong(1, myId[i]); // this matches the first "?"
upd.execute();
}
db.setTransactionSucessful();
db.endTransaction();
}

Android + Sqlite : Table creation sql has no effect

I am trying to create a simple android application which creates a database using SQLiteDatabase (not using SQLiteOpenHelper). So the database creation and the table creation sql executes successfully without any issues/exceptions.
Now the issue is when I reopen the same database, the earlier table created does not exist!!
I am checking the existence of the table using the following code :
Cursor cursor = db.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '"+ sqlQueryString +"'", null);
if(cursor!=null) {
if(cursor.getCount() == 0) {
//error handling code here
}
cursor.close();
}
Obviously am ending in the if(cursor.getCount() == 0) condition.
I pulled the db file and also checked with a sqlite viewer on the pc, the table created earlier simply does not exist.
So my question is how do I verify that my create table query has created the table properly?
Adding requested information:
Create table ExampleTable ( ROWID integer primary key autoincrement , FIRSTNAME text , LASTNAME text ) ;
Adding the android code the execute the above query:
db.beginTransaction();
db.execSQL(sqlQueryString);
db.endTransaction();
You need to call db.setTransactionSuccessful() before you end the transaction, or else the operation is assumed to have failed and the transaction is rolled back.
Typical transaction usage is:
db.beginTransaction();
try {
// execute DB queries here
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Credit to njzk2 for first mentioning the solution in a comment.

SQLiteDatabase.insert() returns incorrect rowid for virtual tables

When I insert a row into a full-text search database declared like:
CREATE VIRTUAL TABLE foo USING fts3 (bar);
the SQLiteDatabase.insert() method returns an incorrect rowid. If the table is declared like:
CREATE TABLE foo (bar VARCHAR(10));
it returns the correct rowid value. The problem is when I query the database soon after the insert using the rowid returned from the method, the returned Cursor has no records. It works correctly for the first insert into the database only. For subsequent inserts, an incorrect rowid is returned.
Is there anything I need to do to get the correct rowid from the SQLiteDatabase.insert() method?
I'm using Android SDK version 2.1update1.
Thanks,
Dan
Update:
I ended up using a hack to get the last row id using the following code:
private int getLastRowId(SQLiteDatabase db, String table) {
Cursor cursor = null;
try {
cursor = db
.rawQuery(String.format(Locale.US, "SELECT MAX(rowid) FROM %s", table), null);
if (cursor.moveToFirst()) {
return cursor.getInt(0);
} else {
return 0;
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
In my case, it's safe because only a single user has access to the app. For service apps, this may not work depending on how it is implemented/used.
I believe we have this problem because when performing an insert in fts3 tables, more than one row is inserted. A row is inserted in the subject table and in the fts3 management tables as well.
From SQLite Full-Text Search:
Your table must contain at least 1
TEXT field.
PS: +1: I didn't know about Virtual Tables. Thanks.

Categories

Resources