I know this question has asked many times in SO,but i couldn't figure out my exact problem.
I am using the following code to get the data from the database(Table1) and update another Table2 based on retrieval value. Its working fine in some android versions but when i gone to test with Android 4.0.3. I am geting this java.lang.IllegalStateException:?.attempt to re-open an already-closed object at sum_cursor.moveToNext();.
I am using this code in AsyncTask.
/** Sum of total matched values*/
Cursor sum_cursor = db.gettotalMatchvalue(this);
if(sum_cursor!=null)
{
sum_cursor.moveToFirst();
for(int j=0; j<sum_cursor.getCount();j++)
{
float totalmatchedscore = sum_cursor.getInt(0);
float totalingredients = Float.parseFloat(sum_cursor.getString(sum_cursor.getColumnIndex(APPDatabase.CK_TOTALINCREDIENTS)));
/**average = totalscore/totalingredients*/
double average = totalmatchedscore/totalingredients;
int id = Integer.parseInt(sum_cursor.getString(sum_cursor.getColumnIndex(APPDatabase.CK_ID)));
db.updateAverage(id, average);
sum_cursor.moveToNext(); //Here is the problem
}
}
db.close();
My update method coding
/** Update average */
public void updateAverage(int id,double average)
{
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(CK_FINALVALUE,average);
db.update(TABLE, values,CK_ID+" = "+id , null);
}
What i am doing wrong here?
I know many of you come across this situation. Could you help me guys.
Thanks for your help.
You can't update a table while iterating over the results of a query. There are good reasons for this; what if the data you are adding would cause a change to the data you're iterating over? Your cursor would not return valid data.
Trying to store data back into the table in updateAverage() is causing the problem. You should just remember the average value during your loop, and then update it once at the end after you've finished looping over your cursor.
To further explain the exact error you're getting: the act of inserting new data is causing the database to close all the cursors which are currently open, as a safety measure. So when you call sum_cursor.moveToNext() after updating the average, the cursor is a bit surprised to find that it's already been closed.
What if you comment out db.updateAverage(id, average) ?
You can achieve your goal with pure SQL it is faster and better from architecture point of View because all logic will be in one SQL transaction
REPLACE INTO table_where_to_put SELECT *, (totalmatchedscore/totalingredients) as average FROM table_with_input_data
Use REPLACE OR UPDATE
Related
I'm trying to fix a DB issue I had in Ankidroid. The following statement was executed:
SELECT count(*) FROM cards c WHERE type = 1 AND combinedDue <
1335153600.000000
It was generated there. The code executed is the following (github link):
cursor = mDatabase.rawQuery(query, null);
if (!cursor.moveToNext()) {
throw new SQLException("No result for query: " + query);
}
I can't understand how I can get no record, I should get either 1 or 0. The call stack in the log was the following:
at com.ichi2.anki.Deck.rebuildRevCount(Deck.java:1351)
Caused by: android.database.SQLException: No result for query: ……
at com.ichi2.anki.AnkiDb.queryScalar(AnkiDb.java:129)
at com.ichi2.anki.Deck._rebuildRevCount(Deck.java:1621)
Any idea?
In fact, I was more looking at a similar case. We have a table «Stats» with a column "global", in which there can be one global record and many daily records. If we don't find (a simple select) the global record, we create it. On my phone, it seems that sometime the global record is not found, so we create an additional one, which break things.
It really look like the case I showed above.
Edit:
I found why. In another thread, an AsyncTask closes the DB at the same time the query is being made (because a lot of processing triggered by the GUI is done asynchronously). And it returns a cursor with no record.
I saw that by adding traces to a file.
Try if (cursor.moveToFirst == false) instead of using the ! operator. I think that the way you are currently doing it is always going to.pass you into the body of the if. And the cursor isn' t properly initialized.without a.moveToFirst.
I have to query three table, and display the data to my customerView.
My code is like this:
Log.v(TAG, System.CurrentTimeMillis())
int len = cursor.getCount();
Log.v(TAG, System.CurrentTimeMillis())
Product[] products = new Product[len];
int i = 0;
while(cursor.moveToNext()){
products[i] = new Product(cursor.getstring(0),.....);
}
Log.v(TAG, System.CurrentTimeMillis())
Sqlite query:
String sql = "SELECT T1.PRODUCT_ID, CODE, SHORT_DESCRIPTION, CATEGORY_CODE,
BRAND_CODE, FORM_CODE, DENOMINATOR, T1.PIECE_PRICE, T1.lowest_piece_price,
T2.sku_type, T1.master_sku " +
"FROM CUSTOMER_PROD_LIST_ITEMS T1 INNER JOIN PRODUCT T2 ON
T1.PRODUCT_ID = T2.ID INNER JOIN PRODUCT_UOMS ON T2.ID =
PRODUCT_UOMS.PRODUCT_ID"+
"WHERE T1.VALID = 1 AND PRODUCT_UOMS.VALID = 1 AND
CUSTOMER_PRODUCT_LIST_ID = " + customer_pdtlist_ID + "
ORDER BY T1.PRODUCT_ID ASC";
After my testing, if we have 1500rows in the cursor, we have to spend more than 30s to finish this line(cursor.getcount()) . If I delete this line, and use ArrayList to take place. i can find that we should spend more than 30s for Cursor.moveToNext().
So my question is why the first time cursor operation should take such long time? and how do we solve?
And this man have the same question Poor SQLite implementation? First time data access way too slow. but the answer is not working for me.
by the way, I find display same 1500rows in Iphone, just need amost 3s.
thanks in advance!!
This is an answer to why the first operation on your cursor is so slow. When a Cursor is backed by SQLite, Android uses the sqlite C library internally and creating a Cursor is analogous to creating a prepared statement in the C library. Creating a prepared statement is cheap and it does not perform any query. Taken from the C library's documentation:
sqlite3_prepare()
This routine converts SQL text into a prepared statement object and returns a pointer to that object. This interface requires a database connection pointer created by a prior call to sqlite3_open() and a text string containing the SQL statement to be prepared. This API does not actually evaluate the SQL statement. It merely prepares the SQL statement for evaluation.
When you call moveToNext() on the Cursor, that's when the query actually gets executed. moveToNext results in a call to the sqlite3_step() function in the C library. Again, taken from the documentation:
sqlite3_step()
This routine is used to evaluate a prepared statement that has been previously created by the sqlite3_prepare() interface. The statement is evaluated up to the point where the first row of results are available. To advance to the second row of results, invoke sqlite3_step() again. Continue invoking sqlite3_step() until the statement is complete. Statements that do not return results (ex: INSERT, UPDATE, or DELETE statements) run to completion on a single call to sqlite3_step().
So creating a Cursor is done lazily and the query is only evaluated when the cursor is first moved.
To find out why the query is taking such a long time, use EXPLAIN QUERY PLAN on your query and see where the bottleneck lies. Usually it's the lack of an appropriate index.
ok, guys, i have not been here for acouple days.And i found the solution that is you have to create index for your table which will improve the query speed. thanks all the same
I've been looking at the notepad tutorial from the android developer site, I'm sorta stuck with two areas - can anyone help?
Firstly the tutorial creates a db with 3 columns: id, title and body. I would like to change the body to a decimal value. Secondly I need to total this column with the decimal value.
So where I have the EditText for the body column is it correct to set the input type to "numberDecimal" in the layout xml? Are any other changes necessary?
How do I then total these the values in this column, should I use be using some sort of loop to go through each record in that column and add them together?
Such as:
int total = 0;
for(int i = 0; i < mydb.table.NumberOfRows; i++) {
total = total + mydb.table.body[i]
}
* apologies I don't even know if a function to count the number of rows exists or how to access a particular part of a table (i suck at SQL and haven't been around java for a while)
Advice would be great!
Just changing the input mode of the EditText view to "numberDecimal" is not enough, but it's a good start, so you can be sure, that you user cannot input any non decimal characters.
To change the data type of the body column, you got to adapt the create statement that is used to create the table. Change the data type from TEXT to REAL so the body column can store float values.
Furthermore you got to adapt the insert statement as the body column is not a TEXT column any longer. So you got to convert the string from the EditText view which represents you numeric value to float before you pass it to the insert statement.
To sum up the all body values, you don't need a loop, you can let the db do this for you using the sum() or total() aggregation function (depending on you needs). The statement will look something like this.
SELECT sum/total(body) FROM <table name>
Replace <table name> with the name of the table.
apologies I don't even know if a function to count the number of rows
exists or how to access a particular
part of a table (i suck at SQL and
haven't been around java for a while)
To loop over the results of a database query you don't need to know how many rows the result has. As a result of a query you get a Cursor object which references the rows returned by the query. To loop over these rows you can use the following statement:
Cursor cursor = queryDB(.......)
while(cursor.moveToNext()){
<do something with the current result row>
}
The fact that you are using the Notepad example as the basis of what your doing, I am correct in assuming that you're using a ContentProvider? Ok so what you have to do is run a query that retrieves ALL the entries in the database:
Cursor c = managedQuery(Notes.CONTENT_URI, new String[] { Notes.BODY }, null, null, null);
Then as you were saying, loop through the cursor:
if (c.moveToFirst()) {
long total = 0;
long body;
int bodyColumn = c.getColumnIndex(Notes.BODY);
do {
// Get the field values
body = c.getLong(bodyColumn);
phoneNumber = cur.getString(phoneColumn);
total += body;
} while (cur.moveToNext());
Does that answer your question? Comment if you need anything specified.
I am working on an answer to a similar question at the moment. I currently thinking that the life of the database would cause a looped tallying method to become very annoying so if I were you I would design the database to keep the tally for you and keep the total input rows. It's just a suggestion but I think it is easier to do two very simple one line methods than one continuously growing recursive/looped method.
i created a database with 6 columns and i have a create and update method in my class that takes 6 parameters/arguments which represent these columns. my problem is that, anytime i try to update or create the database without using all 6 arguments (setting some to null), i get an error "constraint failed". this is most particular with the update method.
any ideas how i can get around this? because sometimes i don't want to fill all columns. I have removed the "text not null" constraint when creating the database. Thank you.
You're going to want to use the ContentValues to achieve this. Heres a quick demo.
My function
public boolean updateStuff(int id,ContentValues args) {
return mDb.update(TableName, args, _id_col + "=" + id, null) > 0;
}
And to call it. Note you can put as many ContentValues as you need
ContentValues initValues = new ContentValues();
initValues.put(col_key,col_value);
Edit:
mDB is a SQLiteDatabase
I think it's kinda easy one but still I'm new to android programming so please have patience. I want to know how can I get the number of records (rows) in a specific table in my db. I need this so I can create a loop to go through every record and add each one of it to the specific Array and display it later on. This is the source:
db.openDataBase(); // open connection with db
Cursor c = db.getTitle(5); // loop here through db, right now I'm fetching only one record
startManagingCursor(c);
//adding areas to the list here
Area o1 = new Area();
o1.setOrderName(c.getString(1) + c.getString(2));
m_areas.add(o1);
db.close();
Does anyone can help me with this please? Thx in advance!
SELECT COUNT(*) FROM tablename
To get the number of rows in the cursor, use getCount.
To get the amount of total rows in a table, either use reinierposts solution, or do a select which select all rows in the table and get the count from the cursor. I'm guessing his solution is quicker though unless you actually need all the rows in the table.
Such a query would be:
SELECT * FROM footable;
You don't really need to get a count of how many first; instead, create a db.getTitles() function that returns all of the rows and returns a Cursor, then loop over the Cursor. Right now you probably have a query that looks something like SELECT ColumnA, ColumnB FROM Titles WHERE id = 5; just copy the function, remove the parameter and take off the WHERE clause so it looks like just SELECT ColumnA, ColumnB FROM Titles.
Then your code would look something like this:
db.openDataBase(); // open connection with db
Cursor c = db.getTitles();
startManagingCursor(c);
//adding areas to the list here
if (c != null && c.moveToFirst()) {
do {
Area o1 = new Area();
o1.setOrderName(c.getString(1) + c.getString(2));
m_areas.add(o1);
} while (c.next());
}
db.close();
We check if the function returned a cursor at all, then move to the beginning of the cursor and start looping, going to the next item each time through. For more information on the Cursor interface see the API here, or to learn more about database access and related design practices better in general I suggest going through the Notepad tutorial.