I have a cursor that contains 3 columns from my database. I need to iterate through, and add the IDs to another table. I tried using the code below, but it caused an "Application not responding" message, and took about 10 seconds to insert all the rows (about 1000).
I have changed the code so that I iterate through the cursor and insert into the DB separately, and this now takes about 500ms. Although it seems I have fixed my problem, I don't understand why.
Can someone please explain why the code below takes so long to execute?
public void setNowPlayingSongs(SQLiteDatabase db, Cursor cursor) {
// Clear all the current songs
db.delete(TABLE_NOW_PLAYING, null, null);
ContentValues cv = new ContentValues();
cursor.moveToFirst();
int index = cursor.getColumnIndex(COL_ID);
while (!cursor.isAfterLast()){
cv.put(COL_SONG_ID, cursor.getInt(index));
db.insert(TABLE_NOW_PLAYING, null, cv);
cursor.moveToNext();
}
}
And why this is so much faster? I don't understand why it's faster to loop through the cursor and then loop through a list. I thought the method above should be faster?
public void setNowPlayingSongs(SQLiteDatabase db, Cursor cursor) {
ContentValues cv;
List<Integer> ids;
int index;
// Clear all the current songs
db.delete(TABLE_NOW_PLAYING, null, null);
// Check which column holds the IDs
index = cursor.getColumnIndex(COL_ID);
// Add the ids to a list
ids = new ArrayList<Integer>();
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
ids.add(cursor.getInt(index));
cursor.moveToNext();
}
// Insert the IDs into the now playing table.
cv = new ContentValues();
db.beginTransaction();
for (Integer id : ids) {
cv.put(COL_SONG_ID, id);
db.insert(TABLE_NOW_PLAYING, null, cv);
}
db.setTransactionSuccessful();
db.endTransaction();
}
When you do individual inserts, each one is actually wrapped in a SQLite transaction. If you instead perform all of your inserts in a single transaction, this should speed things up substantially.
db.beginTransaction();
try {
// do your inserts
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Related
In Udacity's Developing Android Apps, the app they're building displays the weather forecast in a listview, after fetching the data from the openweathermap api. The data is saved into the db via the function bulkInsert shown below. Updates are called by the option "Refresh" in the menu.
No code handles the pruning of old data, and yet the number of rows remains constant in the db after each refresh. Turns out that the last 14 old rows vanish after the loop inserting the 14 new rows. The latter have new row id's.
Example:
We start with:
_id=55
_id=56
_id=57
…
_id=721
_id=722
_id=723
_id=724
_id=725
_id=726
Following the bulk insert, the id list becomes:
_id=55
_id=56
_id=57
…
_id=735
_id=736
_id=737
_id=738
_id=739
_id=740
With the rows 713-726 missing/replaced. Code for bulkinsert:
#Override
public int bulkInsert(Uri uri, ContentValues[] values) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
switch (match) {
case WEATHER:
db.beginTransaction();
int returnCount = 0;
try {
for (ContentValues value : values) {
normalizeDate(value);
long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, value);
if (_id != -1) {
returnCount++;
Log.i(“id:”, " "+_id);
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
getContext().getContentResolver().notifyChange(uri, null);
return returnCount;
default:
return super.bulkInsert(uri, values);
}
}
insert is the vanilla SQLiteDatabase method, which is not supposed to mess with existing rows. Yet, when the line is commented out, the old rows remain in the db.
Any clue what's going on?
my app should delete a specific row in the sql database by this method
public void delete(int id){
open();
sqLiteDatabase.delete("item","id = "+id,null);
close();
}
and it should also delete all rows if the user want that by this method
public void deleteAll(){
cursor=sqLiteDatabase.rawQuery("select * from item",null);
cursor.moveToFirst();
i=1;
while (!cursor.isAfterLast()) {
sqLiteDatabase.delete("item","id = "+i,null);
i++;
System.out.println(i);
cursor.moveToNext();
}
}
when the user use deleteAll() alone it is work but when he use it after using delete() it delete all rows before the deleted one using delete()
is the problem in deleteAll() method ? and how to fix it?
Your delete() function only deletes rows with the given id. If you want to delete all rows, then just do
sqLiteDatabase.delete("item", null ,null);
There is no reason to write your own loop especially since you never use the Cursor anyway.
Additionally, you should never use string concatenation for the "where" clause in a SQL statement. Instead use "id = ?" and provide a String[] with the values:
db.delete("image","id= ?", new String[] {id});
Here is an example of how to delete a particular column with an id:
SQLiteDatabase db= this.getWritableDatabase();
db.delete("image","id= ?", new String[] {id});
Toast.makeText(context,"Delete successfully",Toast.LENGTH_LONG).show();
Hope this will work for you
I have the following insert statement in my app which work.
Before the insert I want to first check the database if the value name does not exist in the name column.
If it does not exists I want to continue with the insert, else display an error message.
How do I incorporate it into my existing statement below?
public void insert(HashMap<String, String> queryValues){
SQLiteDatabase database = this.getWritableDatabase();
ContentValues values = new ContentValues();
Cursor c = database.query("SELECT * FROM user_details where" + "name=?", new String[] {values.put("name") });
if (c.getCount() > 0) {
// don't do it
return;
}
else {
values.put("name", queryValues.get("name"));
values.put("age", queryValues.get("age"));
database.insert("user", null, values);
}
database.close();
}
The correct way to do this is to add a unique constraint on the name field, and then use insertWithOnConflict() with a last argument of CONFLICT_FAIL. That's actually the default behavior. Your insert will fail if it would otherwise cause a constraint violation (insert() will return -1).
If you don't want to do that, there's no magic. Query your DB for a row with the given name field. If you are returned >0 rows, don't perform the insert.
Cursor c = db.query(..., "name=?", new String[] {theName}, ...);
if (c.getCount > 0) {
// don't do it
return;
}
I had created two table in my database, In both table I am inserting value at the same time, now what I want to do is that, I want to insert record in second table, but the condition is that, if there is two same record then I want insert only one record not duplicate value, In second table there is two field one is id and second is category, when user insert two same category that time I want to insert only one entry, below is my code which is not working properly, It insert all record accept duplicate value..
public long InsertCat(String idd, String cat)
{
try
{
SQLiteDatabase db;
long rows = 0;
db = this.getWritableDatabase();
ContentValues Val = new ContentValues();
Val.put("IDD", idd);
Val.put("Category", cat);
Cursor c = db.rawQuery("SELECT * FROM " + TABLE_CATEGER + " WHERE Category='"+cat+"'",null);
while(c.moveToNext())
{
if(c.getString(0).equals(cat))
{
flag=true;
}
}
if(flag==true)
{
rows=db.update(TABLE_CATEGER, Val, "Category='"+cat+"'" , null);
System.out.print(rows);
db.close();
}
if(flag==false)
{
rows = db.insert(TABLE_CATEGER, null, Val);
System.out.print(rows);
db.close();
}
return rows; // return rows inserted.
} catch (Exception e) {
return -1;
}
}
Put all your values inside ContentValues and then call this on writableDatabase
db.insertWithOnConflict(tableName, null, contentValues,SQLiteDatabase.CONFLICT_REPLACE);
EDIT:
Well all you need is only this part of code
SQLiteDatabase db;
long rows = 0;
db = this.getWritableDatabase();
ContentValues Val = new ContentValues();
Val.put("IDD", idd);
Val.put("Category", cat);
rows = db.insertWithOnConflict(tableName, null, contentValues,SQLiteDatabase.CONFLICT_REPLACE);
insertWithOnConflict methods follows the last parameter as the reaction algorithm when an duplicate row is Found. And for a duplicate row to be found, the primary keys has to clash. If all this satisfys the row would surely get Replaced :-/ If not something else is going wrong..
While creating your table, put constraint on your column(Primary key or Unique key).This will not only the duplicate value to be inserted into your database.
This is working for me,and i also created Category as a primary key..
ContentValues Val = new ContentValues();
Val.put("IDD", idd);
Val.put("Category", cat);
long rows=db.insertWithOnConflict(TABLE_CATEGER, null, Val,SQLiteDatabase.CONFLICT_REPLACE);
System.out.print(rows);
Log.d("kkkkkkkkkk",""+ rows);
db.close();
return rows; // return rows inserted.
Check with the primary key of which you want assign then while inserting check with on duplicate key..
if you want you update the row
on duplicate key update
As mentioned i am writing the code on duplicate key
INSERT OR REPLACE INTO TABLE_CATEGER(value1,value2,value3)
Use the following query
INSERT OR REPLACE INTO table_name (idColoumn, categoryColumn) VALUES (?, ?)
It will add new row if it does not exist or update row if it exists.
hope this will help you.
use insertWithOnConflict() method instead of insert()
response = sqLiteDatabase.insertWithOnConflict(TABLE_TRACKER_LOGS_LINES, null, contentValues,SQLiteDatabase.CONFLICT_REPLACE);
I want to insert data successfully
Here is my code:
public void insertData(String strTableName,
ArrayList<HashMap<String, String>> arrListproductdatabase) {
db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
for (int i = 0; i < arrListproductdatabase.size(); i++) {
// cv.put(columnName, arrListOfRecord.get(i).get("name"));
cv.put(columnproductname,
arrListproductdatabase.get(i).get("product"));
cv.put(columnproductprice,
arrListproductdatabase.get(i).get("price"));
cv.put(columnproductquantity,
arrListproductdatabase.get(i).get("quantity"));
cv.put(columnproductid,
arrListproductdatabase.get(i).get("productID"));
cv.put(columnresturantID,
arrListproductdatabase.get(i).get("resturantID"));
db.insert(strTableName, null, cv);
}
I want that when I have to press add button again, that time it should check if the product is already inserted, and in that condition it should update and all.
I don't want to create any duplicate value.
Any help would be appreciated!
you can check for the distinct values in the db. please follow the link to have more details
android check duplicate values before inserting data into database
Set 'Product' field as unique key. So when duplicate value arrives from standard insert, it will simply return -1 and the error message will be swallowed.
You can control the behavior by using insertWithOnConflict (String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm) where you also specify a conflict algorithm that can be of values:
CONFLICT_ABORT
CONFLICT_FAIL
CONFLICT_IGNORE
CONFLICT_REPLACE
CONFLICT_ROLLBACK
Check out the reference for descrption of the conflict resolution types.
There is also an updateWithOnConflict
You can do that like this :
public boolean checkProduct(String product){
// shold open database here
Cursor mCursor =
db.query(true, DATABASE_TABLE, null, "product='" + product+"'", null, null, null, null, null);
if(mCursor != null){
mCursor.close();
// shold close database here
return true;
}
// shold close database first here also
return false;
}
Hope this helped you.