I have a simple SQLite database with two columns.
Col 1 SimpleDateFormat("yyyyDDD") For example 2017001 (for jan 1st, 2017)
Col 2 int of hourly occurances
So each day has a unique code and each day has 24 rows of varying occurances.
How can I get the sum of occurrences for each day sent to an ArrayList(Float)? Eventually this ArrayList will populate an MPAndroidChart. I've successfully pulled the data (without the sum) with the following code. But getting the daily sum with help of my date code has eluded me for days. I've tried many variations of GROUP BY and SUM only to have each crash.
public ArrayList<Float> getOccChartData(){
SQLiteDatabase db = this.getWritableDatabase();
ArrayList<Float> yNewData = new ArrayList<>();
String query = "SELECT OCC FROM user_table ORDER BY ID DESC LIMIT 96";
Cursor c = db.rawQuery(query, null);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
yNewData.add(c.getFloat(c.getColumnIndex("OCC")));
}
c.close();
return yNewData;
}
It's unclear whether or not you want the sums instead of or with the rows, so assuming that you just want the sums, then perhaps you could do:-
public ArrayList<Float> getOccChartData(){
SQLiteDatabase db = this.getWritableDatabase();
ArrayList<Float> yNewData = new ArrayList<>();
String query = "SELECT SUM(OCC) AS OCC FROM user_table GROUP BY ID ORDER BY ID DESC"
Cursor c = db.rawQuery(query, null);
while(c.moveToNext) {
yNewData.add(c.getFloat(c.getColumnIndex("OCC")));
}
c.close();
return yNewData;
}
Example
For example assuming your table has (not 24 rows per table for brevity) :-
The the above would result in the cursor containing the following :-
Note! reversal due to ORDER BY DESC (so latest data first).
i.e. for 2017001, 15 + 20 + 30 + 40 = 105 the last row.
yNewData would have 3 elements accordingly:-
yNewData[0] would be 48,
yNewData[1] would be 50 and
yNewData[2] would be 105.
Alternative considerations
If you wanted a range of days then you change the SELECT to be something like :-
SELECT SUM(OCC) FROM user_table WHERE ID BETWEEN 2017001 AND 2017002 GROUP BY ID ORDER BY ID DESC
Where the values 2017001 and 2017002 would be generated according to the required logic and placed into the query string.
In which case the resultant returned data would be :-
yNewData[0] would be 50 and
yNewData[1] would be 105.
If you want all intermediate values as well as the sums then matters would be more complex as in effect you are returning two types of data in a single dimension array.
The above as an SQL Fiddle
Here's the above as a SQL Fiddle
Related
I want sum values of the column, but I want to summarize the values by skipping the first value and starting to summarize the second in a row. My code
public int sumColum(){
SQLiteDatabase db = this.getReadableDatabase();
Cursor result = db.rawQuery("select sum(PRICE) from wedding_table", null);
if(result.moveToNext())
return result.getInt(0);
return 0;
}
SQL tables represent unordered sets, so there is no first price, unless another column specifies the ordering.
If you mean the highest or lowest price, then it is pretty easy -- assuming there are no duplicates:
select sum(PRICE) - min(price)
from wedding_table;
I have a Person object that I store in a SQLite database.
Person has Age, FirstName, and LastName.
At a given moment, I want to find the youngest person (lowest Age).
How can I do this?
So far I have this:
public Person getYoungest(Cursor c) {
c.moveToFirst();
db.rawQuery("SELECT MIN(" + AGE + ") FROM " + PERSON_TABLE, null);
// Person youngestPerson = ???
// return youngestPerson;
}
However, I'm really confused at what the "rawQuery" does. It doesn't return a person object. Also, I'm not sure whether the query gives me the lowest "age", or the record containing the lowest "age" (which is what I want). I'm very new to SQL, so this is all strange to me.
Any advice?
What you are currently doing is querying for smallest age value from your dataset. If you want to get the whole data row of such you need to use ORDER BY, like
SELECT * FROM ... ORDER BY age ASC LIMIT 1
which would sort the data by Age in ascending order. As you want just one we use LIMIT to ensure this is going that way (and to make things faster), yet note that most likely many records may have the same age (incl. lowest value) so you may extend ORDER BY to fine tune sorting.
SQLite returns strings, numbers, byte arrays.
They are not like java-objects. You have to retrieve your each value and initialize your person in the code using a constructor.
Or use realm database that easily helps to store java-objects using sqlite.
do not forget to improve the performance by using
SELECT * FROM ... LIMIT 1
like Marcin Orlowski said.
to retrieve the data use this:
if (c.moveToFirst()) {
int idColIndex = c.getColumnIndex("id");
int nameColIndex = c.getColumnIndex("name");
int emailColIndex = c.getColumnIndex("email");
int id = c.getInt(idColIndex)
String name = c.getString(nameColIndex)
String email = c.getString(emailColIndex)
to create an object use this:
new Person(<your values>);
db.rawQuery ==> return a Cursor which point to the returned data from select statement so you should make
Cursor cursor = db.rawQuery("SELECT * FROM PERSON_TABLE ORDER BY age ASC , null);
if(cursor.moveToFirst()) //mean find data and point to the samllest
cursor.getString(c.getColumnIndex("field_name"));
I have the following tables in an sqlite database:
items
______
_id (PK)
name
section_subsection_id (FK)
section_subsections
______
_id (PK)
section_id (FK)
subsection_id (FK)
subsections
______
_id (PK)
name
sections
______
_id (PK)
name
I would like to provide a certain keyword to subsections that would only grab only those that match this keyword under a limit, say x, and count all the items under this section AND subsection match.
I have used several queries, here is one:
String selectQuery = "Select subsections.name, subsections._id, temp.count as count
FROM subsections LEFT JOIN
sections_subsections ON subsections._id = sections_subsections.subsection_id
JOIN items (SELECT count(items._id) as count from items) temp
ON items.section_subsection_id = sections_subsections._id
WHERE subsections.name LIKE 'keyword' AND sections_subsections.section_id = 1 ORDER BY
subsections.name ASC LIMIT 50 OFFSET 0 ";
When I try to iterate through the results, I get the list matching the keyword search but the count always displays the last count value from the result set. When I run the raw query in sqlite shell, I see the correct counts in the column with the respective rows, but iterating through the cursor in Android/Java seems to have a problem. Or possibly my query?
So for ListView in the app I would get same counts (that is all 20s), but in shell I see count with correct value. In fact, during cursor iteration, if I Log.d count to the screen it is also all 20s, yet the other column value name is different. What is wrong with my query? Or how do I correctly iterate through a table with multiple joins?
_id name count
---------------
1 item1 79
2 item2 30
3 item3 20
EDIT:
I'm doing something like this in Java:
Cursor cursor = sqliteDatabase.rawQuery(selectQuery, null);
if (cursor != null) {
cursor.moveToFirst();
}
if (cursor.moveToFirst()) {
do {
SubSection subSection = new SubSection();
subSection.setId(cursor.getInt(cursor.getColumnIndex(KEY_ID))); subSection.setSubSectionName(cursor.getString(cursor.getColumnIndex(KEY_TABLE_SUBSECTIONS_SUBSECTION_NAME)));
subSection.setRecords(cursor.getColumnIndex("count"));
subSections.add(subSection);
}
while
(cursor.moveToNext());
}
try below query
Select subsections.name, subsections._id, (SELECT count(items._id) from items WHERE items.section_subsection_id = sections_subsections._id) as count
FROM subsections LEFT JOIN
sections_subsections ON subsections._id = sections_subsections.subsection_id
WHERE subsections.name LIKE 'keyword' AND sections.name = 'Category' ORDER BY
subsections.name ASC LIMIT 50 OFFSET 0 ";
Thanks Syed Waqas, your answer is correct for joining. The problem was not my queries actually. It was my cursor call. I should have used: cursor.getInt(cursor.getColumnIndex("count")) instead of what I have in my original question. I don't know how I managed to not notice this big mistake. For everyone else, you can debug your cursor with the lovely DatabseUtils. :)
Log.d(LOG, "ROW: " + DatabaseUtils.dumpCursorToString(cursor));
I designing a custom ListView ,which has more child view
I have ideas about sorting the ListViewdata in "Asc" or "Desc" order ,that retrieves data directly from database , but in my case I used CustomSimpleCursorAdapter , I requires to sort data in TextView depending upon the values that is:
today
tomorrow
more than 2 days i.e; 354
CustomSimpleCursorAdapter .java
//Days remaining for BirthDay
String year=cursor.getString(cursor.getColumnIndex(BirthdayProvider.EVENT_YEAR));
String month=cursor.getString(cursor.getColumnIndex(BirthdayProvider.EVENT_MONTH));
String date=cursor.getString(cursor.getColumnIndex(BirthdayProvider.EVENT_DATE));
String remainingDays=BirthdayCalculation.getDaysRemainingForNextBirthDay(year, month, date);
Calendar today=Calendar.getInstance();
int CMonth=(today.get(Calendar.MONDAY)+1);
int CDate=(today.get(Calendar.DAY_OF_MONTH));
//checking whether the BD is on TODAY
if (remainingDays.equals("1") && (CDate==Integer.parseInt(date) && (CMonth)==Integer.parseInt(month))) {
viewHolder.txtDaysRemainigValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
viewHolder.txtDaysRemainigValue.setTypeface(fontRoboto_Regular);
viewHolder.txtDaysRemainigValue.setTextColor(Color.parseColor("#00CC33"));
remainingDays="today";
}
//checking whether the BD is on TOMORROW
else if (remainingDays.equals("1")) {
viewHolder.txtDaysRemainigValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);
viewHolder.txtDaysRemainigValue.setTextColor(Color.parseColor("#FF0099"));
remainingDays="tomorrow";
viewHolder.txtDaysRemainigValue.setTypeface(fontRoboto_Regular);
}
//checking how many days remaining BD
else{
remainingDays=BirthdayCalculation.getDaysRemainingForNextBirthDay(year, month, date);
viewHolder.txtDaysRemainigValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, 27);
viewHolder.txtDaysRemainigValue.setTextColor(Color.parseColor("#990000"));
}
Here's Screen Shot link
When you query your database, you should use an "order by" clause. For example, this method takes the order by clause as the last argument. I don't know how you store your dates and times in your database, but if it's something SQLite can recognize and provide sorting on, then it should work. The following will query for all columns on a table named "table" with no where clause, no "group by" clause, no "having" clause, and order by the time column descending (use ASC for ascending if you want that instead):
database.query("table", null, null, null, null, null, "time DESC");
EDIT
If you can't store the exact data you want (in this case days remaining until an event), I can only see two options:
1). After getting the cursor, you iterate over the results and compose a new sorted list. You could make some kind of model object in java, read the values into it from the cursor, and sort them with a comparator function. At that point you probably would not use a CursorAdapter any more. It's quite easy to build your own ListAdapter - I recommend you watch The World of Listview
2). Since the query methods take strings, you can actually compose more complicated queries so that SQLite provides you the data you DO want (and still sort it for you as well). If your times are stored as longs, you could do something like this:
long currentTime = System.currentTimeMillis();
String timeAsString = Long.toString(currentTime);
String remainingTimeColumn = "(time_column - " + timeAsString + ") AS remaining_time";
// compose query
String table = "table";
String[] columns = new String[] {"column1", "column2", ..., "columnN", remainingTimeColumn};
String order = "remaining_time ASC";
// query
Cursor cursor = database.query(table, columns, null, null, null, null, order);
// later, get remaining time from cursor row
long remainingTime = cursor.getLong(cursor.getColumnIndex("remaining_time"));
In this case "time_column" is the name of the column that stores the event time. What this is doing is creating an additional column with the name "remaining_time", which is calculated from one of the actual column values. The results are then sorted by that synthesized column. The cursor you get back will contain this column and these values, you just need to have the proper column name to access them.
Since I don't know the details of your data format, I can't say this is exactly how your query should look, but the idea should be clear. You can work out the finer details from here...
If you get the data in database, you can use ASC or DESC and put ArrayList.
another way is you can use Collections.sort(). but you must data class implements comparable and overriding compare method.
I'm getting poor performance and possibly strange behavior with a simple SELECT query in Sqlite & Android. SqliteDatabase.query() executes my query in only 1 ms, but fetching the results with Cursor.get*() takes over 150 ms to return only 8 rows!
I am trying to find all the rows in the table english where the column word starts with "prefix" (an arbitrary string), sort the results by the row column, and return only the first 8 results.
Here is my code:
String columns[] = {"word", "rank"};
Cursor cursor = mDB.query("english", columns, "word LIKE '" + prefix + "%'", null, null, null, "rank,word", "8");
// It takes only 1 ms to get here
String word = "";
int rank = 0;
if (cursor.moveToFirst()){
do {
word = cursor.getString(0);
rank = cursor.getInt(1);
}
while(cursor.moveToNext());
}
cursor.close();
// It takes over 150 ms to get here!
The table definition for english is:
CREATE TABLE en (_id INTEGER PRIMARY KEY, word TEXT, rank INTEGER)
It contains about 65,000 entries. It also also indexes on word and rank, with a third index for both (I was getting desperate!):
CREATE INDEX "rank" ON "en" ("rank" ASC)
CREATE INDEX "word" ON "en" ("word" ASC)
CREATE INDEX "word_rank" ON "en" ("word" ASC, "rank" ASC)
Thanks in advance!
The query method doesn't actually retrieve all the data, the cursor retrieves it as it moves through the rows. So it makes sense that the Cursor.move*() methods are slower then the query.
This 'lazy-loading' concept helps save memory as only the relevant data is retrieved as it's needed.
As for performance, you really aren't doing anything wrong. Are you trying this on the emulator? Perhaps try it on an actual device and test the performance.