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.
Related
Is it possible to use ContentValues.put() to update a column in a SQLiteDatabse to be the sum of other columns?
I have searched on here and on the web and the closest answer I have found is: Update one column as sum of other two columns. This doesn't quite answer my question because it requires a raw database command, which I would prefer to avoid (if possible).
I have a fairly static database that I have generated unique permutations in (long setup, fast queries). I am attempting to set a total column at the end for even faster sorting on the permutations. I am currently attempting to use:
ContentValues values = new ContentValues();
values.put(totalVal, sumString);
where I have tried to set sumString to both:
=val_1+val_2+val_3...
and
val_1+val_2+val3...
When I look at my database in adb shell, sqlite3 I see:
Which looks... correct? Except when I query my database after this has been set, I get this in the log:
My val_* columns show values in the same adb shell, sqlite3 dump. Also, I do not set the totalVal column to this sumString until the val_* columns are all populated with their values.
Is it just not possible to use ContentValues.put()? Does it do some sort of internal escaping?
The reason it seems like it should work to me is the totalVal column is set to REAL so if ContentValues.put() does do internal escaping I thought I would get an error since I would essentially be putting a String value in a column that should only accept REAL.
Like I said earlier, my database is pretty static and only there for fast queries and sorting. It would be possible for me to loop through all the val_* columns and manually sum them up. Although, there are thousands of rows in my database so I was hoping to avoid this and was looking for a more elegant way to do this.
Thanks for the help.
SQLiteDatabase.update() is just a convenience method for updating rows in the database, so in your case you are just overcomplicating things trying to use ContentValues instead of SQLiteStatement and binding arguments which is what SQLiteDatabase.update() uses internally but preventing that column names were considered Strings.
It's not very clear from your example but if you are trying to update some values and at the same time calculate the totalVal do something like this
SQLiteStatement stmt = db.compileStatement("UPDATE mytable SET val_1=?, val_2=?, val_3=?, totalVal=val_1+val_2+val_3 WHERE expr");
stmt.bindLong(1, 1);
stmt.bindLong(2, 3);
stmt.bindLong(3, 5);
stmt.executeUpdateDelete();
EDIT
So as mentioned in your comment you don't need to bind values, it's even simpler
final int rows = db.compileStatement("UPDATE mytable SET totalVal=val_1+val_2+val_3").executeUpdateDelete();
and regarding your comment about "raw" SQL, ContentValues are not an option so this is the only way (AFAIK).
I want to write a query that add up all the rows that have the string value of "left" in column named DIRECTION. Next I want to return this sum.
In my code snip-it below assume data and data base are established.
Here is the prototype:
public int getSumLeft() {
String selectQuery = "SELECT COUNT( "+TableData.TableInfo.DIRECTION+" ) WHERE "+TableData.TableInfo.DIRECTION+" = left";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
cursor.moveToFirst();
int sum = cursor.getInt(0);
cursor.close();
return sum;
}
I've tried several queries and this one seems to be the closes to what I need. I think the problem is with statement 'int sum = cursor.getInt(0);'
I think the zero parameter is overriding the results. When I remove the zero the code breaks. getInt is an SQLite function that is used to access data in the database. I did not create that function. But I must use it or and another function like it.
Also, do I need to put a while loop around the query to move the cursor for a COUNT query? Doesn't the Database count for you, therefor no need for iteration?
Is there another way of counting the rows where the string value is 'left' and the sum can be returned?
Full code here:
Database:
https://github.com/Leoa/Accelerometer/tree/AccelerometerDEV/app/src/main/java/thedatabase
Implementation (see the button in onCreate function ):
https://github.com/Leoa/Accelerometer/blob/AccelerometerDEV/app/src/main/java/com/leobee/accelerometer/MainActivity.java
Thanks for looking into this.
I think the zero parameter is overriding the results
I have no idea what you think that this means.
When I remove the zero the code breaks
That is because getInt() needs to know the column of the Cursor to retrieve.
You are also crashing at runtime, as your SQL is invalid. Your SQL statement amounts to:
SELECT COUNT(foo) WHERE foo = left
(where foo is whatever TableData.TableInfo.DIRECTION in Java refers to)
Not only does your SQL statement lack a table to query against, but if left is supposed to be the value of a string column, you need to quote it. You will wind up with something like:
SELECT COUNT(foo) FROM tablename WHERE foo = 'left'
do I need to put a while loop around the query to move the cursor for a COUNT query?
No.
Is there another way of counting the rows where the string value is 'left' and the sum can be returned?
Not really, other than the fix that I outline above.
I think the problem is you need to add quotes on the 'left'
String selectQuery = "SELECT COUNT( "+TableData.TableInfo.DIRECTION+" ) WHERE "+TableData.TableInfo.DIRECTION+" = 'left'"
I have put an sqlite database in my assets folder and imported it onto the phone.
I created an object with multiple properties and when I create a list of that object and assign each property a value from a column of the table they get mixed up
Below is my code
public ArrayList<Exercise> getExercisesFromQuery(String Query) {
ArrayList<Exercise> ExerciseList = new ArrayList<Exercise>();
Cursor cursor = mDb.rawQuery(Query, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Exercise e = new Exercise();
e.setID(Integer.parseInt(cursor.getString(0)));
e.setName(cursor.getString(1));
e.setMuscle(cursor.getString(2));
e.setDescription(cursor.getString(3));
e.setFilepath(cursor.getString(4));
e.setSets(cursor.getString(5));
e.setReps(cursor.getString(6));
e.setEquipment(cursor.getString(7));
e.setPrimaryMuscle(cursor.getString(8));
e.setSecondaryMuscle(cursor.getString(9));
e.setDifficulty(cursor.getString(10));
// Adding contact to list
ExerciseList.add(e);
} while (cursor.moveToNext());
}
return ExerciseList;
}
The current problem is when I do object.getName it gives me the muscle and if I do object.getmuscle it is blank and there is no value but if I do object.getDescription it works fine.
It is not a problem with the database it works fine in any sqlite manager.
Any ideas as to what is wrong?
The reason why the columns are not being returned in the order you expect is not clear. They should come back in the order specified in your query or in the order they are on the table if you are doing SELECT *. However it is not really necessary to address that specific puzzle.
A more defensive and maintainable coding approach is to request each column's index from the cursor by using the getColumnIndexOrThrow method instead of hardcoding them. For example:
int ID_INDEX = cursor.getColumnIndexOrThrow("_id");
int NAME_INDEX = cursor.getColumnIndexOrThrow("name");
If the column doesn't exist you'll get an exception. If it does, you now have its index within the cursor which you can use in the calls to cursor.getString:
e.setID(Integer.parseInt(cursor.getString(ID_INDEX)));
e.setName(cursor.getString(NAME_INDEX));
So you no longer need to worry about what order the columns come back in and you won't need to change any hardcoded index values if your query changes in the future.
Make sure that the columns in the database are in the correct order - column Name should be the second column, column Muscle should be the third column.
I have two columns in my SQLite Database, name and score. I need to display the out put of all table records by score descending from highest value. I have this working at the moment but due to score being a String, of course it only goes by the first number in the string, so 30 is above 200 etc...
Here is my SQL code:
private static final String fields[] = { "name", "score", BaseColumns._ID };
Cursor data = database.query("scores", fields, null, null, null, null, "score DESC");
I have no idea how I can continue to use the above code as well as converting all of the score values to integers in order to sort by highest score first. I started to do this by converting each score value into an integer and store it in an array in order to sort them, but then I only have half of my information, so this was a bad idea, I had not thought through.
I spent about an hour reading the SQLite documentation in order to seek some way of doing this more efficiently as well as scour Stackoverflow, but to no avail. Can anyone provide advice on how I should proceed to do this?
This answer solves the problem by casting the strings as integers in the query. This is better than doing it in the program because the database is built for storing and sequencing large amounts of data, so it is much more efficient to change the query than the code.
I think the right answer is to store them as their correct type, since you only do that once when you INSERT. Why reformat every time you query and display? Makes no sense to me.
I'm working to develop an application that has to query at some time, a database with over 4k rows, and each row has 90 fields (Strings). The problem is that if I select * from database, my cursor gets really big (over 4MB). And the cursor in android is limited to 1MB.
How can I solve this, or what's the most elegant method to workaround this?
It is possible to split database in smaller chunks and query them out?
I found a way to handle this and I want to share with all who need it.
int limit = 0;
while (limit + 100 < numberOfRows) {
//Compose the statement
String statement = "SELECT * FROM Table ORDER someField LIMIT '"+ limit+"', 100";
//Execute the query
Cursor cursor = myDataBase.rawQuery(statement, null);
while (cursor.moveToNext()) {
Product product = new Product();
product.setAllValuesFromCursor(cursor);
productsArrayList.add(product);
}
cursor.close();
limit += 100;
}
//Compose the statement
String statement = "SELECT * FROM Table ORDER someField LIMIT '"+ (numberOfRows - limit)+"', 100";
//Execute the query
Cursor cursor = myDataBase.rawQuery(statement, null);
while (cursor.moveToNext()) {
Product product = new Product();
product.setAllValuesFromCursor(cursor);
productsArrayList.add(product);
}
cursor.close();
The main idea is to split your data, so you can use the cursor as it should be used. It's working under 2 s for 5k rows if you have indexed table.
Thanks,
Arkde
Well as a rule you never do select *. For a start each row will have a unique identifier, and your user will want to select only certain rows and columns - ie what they can see on an android screen. Without appearing to be rude this is a pretty basic question. You only return the columns and rows you want to display for that screen on the phone - otherwise you consume unnecssary battery life transfering never to be diaplayed data. the standard approach is to used parameterised stored procedures. Google parameterised stored procedures and do a little reading - by the by - you cant update any table unlees you return the unique row identifier for that table.
Do you need all these rows at the same time? Can you fetch them in parts? This question has been asked several times: Android SQLite and huge data sets
Here's one more suggestion: If you have 90 fields that you need to modify, split them into 10 different views. On each view have a left arrow and right arrow so you can horizontally traverse across screens. Hence each view will show 9 fields. Or some strategy like that. Essentially these are all the same views except for column names so you shouldn't have to modify much code.