I have the following two queries:
A.
db.query(DBHelper.TABLE, new String[] {
DBHelper._ID, DBHelper._DATE_AND_TIME,
DBHelper._SOURCE, DBHelper._MODE,
"SUM(" + DBHelper._AMOUNT + ")" },
DBHelper._DATE_AND_TIME + " BETWEEN ? AND ?",
new String[] { date_min, date_max }, null, null, null, null);
and result of sum goes to textview like this
String.valueOf(cursor.getString(4)).
Second query B.
db.query(DBHelper.TABLE, new String[] {
DBHelper._ID, DBHelper._DATE_AND_TIME,
DBHelper._SOURCE, DBHelper._MODE,
DBHelper._AMOUNT }, DBHelper._DATE_AND_TIME
+ " BETWEEN ? AND ?", new String[] { date_min, date_max },
null, null, null, null);
and result goes to
adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, from,
to, FLAG_AUTO_REQUERY);
What I want is to combine both queries. Close cursor after first query and to use same query (A) for adapter. So far I have added DBHelper._AMOUNT to SELECT of A query but ListView shows only the last entry result (not the whole data). How can I modify query A for showing SUM in TextView and then use same query for adapter.
In a normal query (like B), the database returns a result record for each table record that matches the WHERE filter.
However, when you are using an aggregate function like SUM(), the database computes a single value from all table records (or from all records in a group if you're using GROUP BY) and returns that as a single result record.
Therefore, your two queries are fundamentally different and cannot be combined into a single query.
(Please note that the first four result columns of your query A do not have any meaningful value because the result record is not guaranteed to correspond to any particular record in the original table; you should ask only for the SUM value.)
Related
I have two tables atm, users and notes. I am trying to retrieve data that belongs to the user. So all data to list must be owned by the original user and shown only to him. I have made my table in Databasehelper.
I have made a new class that controls the notes table. In listNotes() I want to loop through the cursor row and get all data owned by the user. Am I quering it correctly?
// Listing all notes
public Cursor listNotes() {
Cursor c = db.query(help.NOTE_TABLE, new String[]{help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE}, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
db.close();
return c;
}
I then want to display the cursor data collected in a listview
public void populateList(){
Cursor cursor = control.listNotes();
getActivity().startManagingCursor(cursor);
//Mapping the fields cursor to text views
String[] fields = new String[]{help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE};
int [] text = new int[] {R.id.item_title,R.id.item_body, R.id.item_date};
adapter = new SimpleCursorAdapter(getActivity(),R.layout.list_layout,cursor, fields, text,0);
//Calling list object instance
listView = (ListView) getView().findViewById(android.R.id.list);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
}
You aren't creating the NOTE_TABLE right.
You miss a space and a comma here
+ COLUMN_DATE + "DATETIME DEFAULT CURRENT_TIMESTAMP"
It has to be
+ COLUMN_DATE + " DATETIME DEFAULT CURRENT_TIMESTAMP,"
There are two issues here:
One is you have missed a comma (after the Timestamp as specified in an earlier answer).
The other error you have is when using a SimpleCursorAdapter, you need to ensure that the Projection string array includes something to index the rows uniquely and this must be an integer column named as "_id". SQLite already has a feature built in for this and provides a column named "_id" for this purpose (however you can have your own integer column which you can rename to _id). To solve this, change your projection string array to something like:
new String[] {"ROW_ID AS _id", help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE}
I guess the NullPointerException stems from this (but without the stacktrace I don't know for sure).
I use CursorLoader to query a result, which is not the order that I want to show in the ListFramgenet. How to sort it ?
I use this to set the adapter:
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_2, null,
new String[] { "name", "distance"},
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
Create loader :
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getActivity(),
Uri.withAppendedPath(TraceTable.CONTENT_URI, "latest"),
MEMBERS_PROJECTION,
null,
null,
null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.changeCursor(data);
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
Well, there are latitude and longitude the queried results. I want to calculate the distance between my location and these results. and sort by distance asc.
How to sort it? Any answer will be appricated
It's actually quite easy:
from this:
new CursorLoader(getActivity(),
Uri.withAppendedPath(TraceTable.CONTENT_URI, "latest"),
MEMBERS_PROJECTION,
null,
null,
null);
to this:
// You could have them calculated in the projection like this:
String[] projection = { COLUMN1 + " * " + COLUMN2 + " as data", // Whatever your calculations are
COLUMN1, COLUMN2, COLUMN3, etc.. };
new CursorLoader(getActivity(),
Uri.withAppendedPath(TraceTable.CONTENT_URI, "latest"),
projection,
null,
null,
"data ASC");
Remember that if you have some method in your provider that does a check to the
projection and rise an exception, you would have to comment it out for the moment you are doing the test or add the new column (the one you do the calculation with) to your official projection array.
What you're looking for is supplying a sortOrder argument something like the following:
(the ORDER BY at the start of this is implicait and you do not include it, simply included here for clarity)
ORDER BY 6366000*acos(cos(lat_a / (180/3.14169))*cos(lng_a / (180/3.14169))*cos(lat_b / (180/3.14169))*cos(lng_b / (180/3.14169)) + t2 + t3) ASC
(for this I took the answer here and inlined it - except I didn't bother with t2 and t3, because it's not going to work anyway)
Unfortunately, this is impossible in standard SQLite - there are no operators sin, or cos - or even a square root or power operator (after seeing your comment about only requiring a more simple calculation).
You can add your own functions, but that's a somewhat more complicated route.
Depending on how many rows you have, you might be alright to just read them all and then sort them yourself.
Provide the column names you want to sort on as the last parameter of the CursorLoader() constructor as a string. If you have more than one column to sort by, separate with a comma. If you want ascending as opposed to descending, add DESC after the column name. So pretty much what you would add after 'ORDER BY' in regular SQL syntax.
EDIT: To answer your comment below.
Yes and no. I believe you could use that as your sort order but SQLite does not have a sqrt or power function. However you can define your own SQLite functions or use a 3rd party extension. If you don't want to go that route, you'll have to use your own custom adapter instead of SimpleCursorAdapter, e.g. you would get the cursor results and then sort them in code into another data stucture which would become the datasource of your adapter.
Just add ContactsContract.Contacts.SORT_KEY_PRIMARY.
I have an issue with SQLite on android. Right now, I'm pulling a JSON object from a server, parsing it, and putting each sub-object in a Table with things such as the Name, Row_ID, unique ID, etc. using this code:
public void fillTable(Object[] detailedList){
for(int i=0;i<detailedList.length;++i){
Log.w("MyApp", "Creating Entry: " + Integer.toString(i));
String[] article = (String[]) detailedList[i];
createEntry(article[0], article[1], article[2], article[3], article[4], article[5]);
}
}
createEntry does what it sounds like. It takes 6 strings, and uses cv.put to make an entry. No problems.
When I try to order them however, via:
public String[] getAllTitles(int m){
Log.w("MyApp", "getTitle1");
String[] columns = new String[]{KEY_ROWID, KEY_URLID, KEY_URL, KEY_TITLE, KEY_TIME, KEY_TAGS, KEY_STATE};
Log.w("MyApp", "getTitle2");
Cursor c = ourDatabase.query(DATABASE_TABLENAME, columns, null, null, null, null, KEY_TIME);
Log.w("MyApp", "getTitle3");
String title[] = new String[m];
Log.w("MyApp", "getTitle4");
int i = 0;
int rowTitle = c.getColumnIndex(KEY_TITLE);
Log.w("MyApp", "getTitle5");
for(c.moveToFirst();i<m;c.moveToNext()){
title[i++] = c.getString(rowTitle);
Log.w("MyApp", "getTitle " + Integer.toString(i));
}
return title;
}
Each entry actually has many duplicates. I'm assuming as many duplicates as times I have synced. Is there any way to manually call the onUpgrade method, which drops the table and creates a new one, or a better way to clear out duplicates?
Secondary question, is there any way to order by reverse? I'm ordering by time now, and the oldest added entries are first (smallest number). Is there a reverse to that?
If you don't want duplicates in one column then create that column with the UNIQUE keyword. Your database will then check that you don't insert duplicates and you can even specify what should happen in that case. I guess this would be good for you:
CREATE TABLE mytable (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
theone TEXT UNIQUE ON CONFLICT REPLACE
)
If you insert something into that table that already exists it will delete the row that already has that item and inserts your new row then. That also means that the replaced row gets a new _id (because _id is set to automatically grow - you must not insert that id yourself or it will not work)
Your second question: you can specify the direction of the order of if you append ASC (ascending) or DESC (descending). You want DESC probably.
Cursor c = ourDatabase.query(DATABASE_TABLENAME, columns, null, null, null, null, KEY_TIME + " DESC");
I have created a working SQlite database in my application. I can add new values to the database. I have even created a method which displays all the results of the table on a new activity.
What I would this new activity really to do, is to display the most recent entry into text views. Picking individual fields and slotting them into correct text views. How do I go about doing this?
Assuming you are using autogenerated ID in your table, you need to sort the results based on ID and limit the results to '1' which will return only that row.
return db.query(true, "yourTableName", new String[] { "columnNamesYouwanttoQuery" },
null, null, null, null, "_id DESC", "1");
Then loop through the cursor and get yourColumns
Cursor cur = adaptor.getMileageReport(AutoMainActivity.CARNAME);
startManagingCursor(cur);
if (cur.moveToFirst()) {
do {
String retrievedVal = cur.getString(0);
}
}
I query and get a result set back, but I need to do some calculations that are impossible in the SQLite WHERE clause in order to determine what shows up in the ListView. How can I remove certain rows from the cursor? I know it is the same question as this Filter rows from Cursor so they don't show up in ListView but that answer does not help. Can an example be provided if there isn't a simpler way to do this?
It might work to simply retain all the rows in the Cursor, but then use a custom adapter to hide the unwanted rows at display time. For example, if you extend CursorAdapter, then you might have something like this in your bindView implementation:
View v = view.findViewById(R.id.my_list_entry);
boolean keepThisRow = .......; // do my calculations
v.setVisibility(keepThisRow ? View.VISIBLE : View.GONE);
There should be a better way to do this, but what I ended up doing is storing the ID of each row I wanted in a string ArrayList, and then requerying where _id IN arraListOfIds.toString(), replacing the square brackets with parentheses to fit SQL syntax.
// Get all of the rows from the database
mTasksCursor = mDbHelper.fetchAllTasks();
ArrayList<String> activeTaskIDs = new ArrayList<String>();
// calculate which ones belong
// .....
if (!hasCompleted)
activeTaskIDs.add(mTasksCursor.getString(TaskerDBadapter.INDEX_ID));
// requery on my list of IDs
mTasksCursor = mDbHelper.fetchActiveTasks(activeTaskIDs);
public Cursor fetchActiveTasks(ArrayList<String> activeTaskIDs)
{
String inClause = activeTaskIDs.toString();
inClause = inClause.replace('[', '(');
inClause = inClause.replace(']', ')');
Cursor mCursor = mDb.query(true, DATABASE_TABLE, columnStringArray(),
KEY_ROWID + " IN " + inClause,
null, null, null, null, null);
if (mCursor != null) { mCursor.moveToFirst(); }
return mCursor;
}
ContentResolver cr = getContentResolver();
Cursor groupCur = cr.query(
Groups.CONTENT_URI, // what table/content
new String [] {Groups._ID, Groups.NAME}, // what columns
"Groups.NAME NOT LIKE + 'System Group:%'", // where clause(s)
null, // ???
Groups.NAME + " ASC" // sort order
);
The "What Columns" piece above is where you can tell the cursor which rows to return. Using "null" returns them all.
I need to do some calculations that
are impossible in the SQLite WHERE
clause
I find this very hard to believe; my experience has been that SQL will let you query for just about anything you'd ever need (with the exception of heirarchical or recursive queries in SQLite's case). If there's some function you need that isn't supported, you can add it easily with sqlite_create_function() and use it in your app. Or perhaps a creative use of the SELECT clause can do what you are looking for.
Can you explain what these impossible calculations are?
EDIT: Nevermind, checking out this webpage reveals that the sqlite_create_function() adapter is all closed up by the Android SQLite wrapper. That's annoying.