I'm having trouble with something that works in the Notepad example.
Here's the code from the NotepadCodeLab/Notepadv1Solution:
String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);
This code seems to work fine. But just to be clear, I ran the ADB
utility and run SQLite 3. I inspected the schema as follows:
sqlite> .schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE notes (_id integer primary key autoincrement, title text
not null, body text not null);
All seems good to me.
Now on to my application, which, as far as I can see, is basically the same with
a few minor changes. I've simplified and simplified my code, but the
problem persists.
String[] from = new String[] { "x" };
int[] to = new int[] { R.id.x };
SimpleCursorAdapter adapter = null;
try
{
adapter = new SimpleCursorAdapter(this, R.layout.circle_row, cursor, from, to);
}
catch (RuntimeException e)
{
Log.e("Circle", e.toString(), e);
}
When I run my application, I get a RuntimeException and the following prints
in LogCat from my Log.e() statement:
LogCat Message:
java.lang.IllegalArgumentException: column '_id' does not exist
So, back to SQLite 3 to see what's different about my schema:
sqlite> .schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE circles (_id integer primary key autoincrement, sequence
integer, radius real, x real, y real);
I don't see how I'm missing the '_id'.
What have I done wrong?
One thing that's different between my application and the Notepad example is
that I started by creating my application from scratch using the
Eclipse wizard while the sample application comes already put together. Is
there some sort of environmental change I need to make for a new application
to use a SQLite database?
I see, the documentation for CursorAdapter states:
The Cursor must include a column named _id or this class will not
work.
The SimpleCursorAdapter is a derived class, so it appears this statement applies. However, the statement is technically wrong and somewhat misleading to a newbie. The result set for the cursor must contain _id, not the cursor itself.
I'm sure this is clear to a DBA because that sort of shorthand documentation is clear to them, but for those newbies, being incomplete in the statement causes confusion. Cursors are like iterators or pointers, they contain nothing but a mechanism for transversing the data, they contain no columns themselves.
The Loaders documentation contains an example where it can be seen that the _id is included in the projection parameter.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_PRESENCE,
Contacts.PHOTO_ID,
Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// ...
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
This has been answered and I would like to make it more comprehensive here.
SimpleCursorAdapter requires that the Cursor's result set must include a column named exactly "_id". Don't haste to change schema if you didn't define the "_id" column in your table.
SQLite automatically added an hidden column called "rowid" for every table. All you need to do is that just select rowid explicitly and alias it as '_id' Ex.
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cur = db.rawQuery( "select rowid _id,* from your_table", null);
Tim Wu's code really works...
If you are using db.query, then it would be like this...
db.query(TABLE_USER, new String[] {
"rowid _id",
FIELD_USERNAME,
},
FIELD_USERNAME + "=" + name,
null,
null,
null,
null);
Yes , I also change the SELECT string query to fix this issue.
String query = "SELECT t.*,t.id as _id FROM table t ";
What solved my issue with this error was that I had not included the _id column in my DB query. Adding that solved my problem.
This probably isn't relevant anymore, but I just hit the same problem today. Turns out column names are case sensitive. I had an _ID column, but Android expects an _id column.
If you read the docs on sqlite, creating any column of type INTEGER PRIMARY KEY will internally alias the ROWID, so it isn't worth the trouble of adding an alias in every SELECT, deviating from any common utilities that might take advantage of something like an enum of columns defining the table.
http://www.sqlite.org/autoinc.html
It is also more straightforward to use this as the ROWID instead of the AUTOINCREMENT option which can cause _ID can deviate from the ROWID. By tying _ID to ROWID it means that the primary key is returned from insert/insertOrThrow; if you are writing a ContentProvider you can use this key in the returned Uri.
Another way of dealing with the lack of an _id column in the table is to write a subclass of CursorWrapper which adds an _id column if necessary.
This has the advantage of not requiring any changes to tables or queries.
I have written such a class, and if it's of any interest it can be found at https://github.com/cmgharris/WithIdCursorWrapper
Related
I'm having trouble with something that works in the Notepad example.
Here's the code from the NotepadCodeLab/Notepadv1Solution:
String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);
This code seems to work fine. But just to be clear, I ran the ADB
utility and run SQLite 3. I inspected the schema as follows:
sqlite> .schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE notes (_id integer primary key autoincrement, title text
not null, body text not null);
All seems good to me.
Now on to my application, which, as far as I can see, is basically the same with
a few minor changes. I've simplified and simplified my code, but the
problem persists.
String[] from = new String[] { "x" };
int[] to = new int[] { R.id.x };
SimpleCursorAdapter adapter = null;
try
{
adapter = new SimpleCursorAdapter(this, R.layout.circle_row, cursor, from, to);
}
catch (RuntimeException e)
{
Log.e("Circle", e.toString(), e);
}
When I run my application, I get a RuntimeException and the following prints
in LogCat from my Log.e() statement:
LogCat Message:
java.lang.IllegalArgumentException: column '_id' does not exist
So, back to SQLite 3 to see what's different about my schema:
sqlite> .schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE circles (_id integer primary key autoincrement, sequence
integer, radius real, x real, y real);
I don't see how I'm missing the '_id'.
What have I done wrong?
One thing that's different between my application and the Notepad example is
that I started by creating my application from scratch using the
Eclipse wizard while the sample application comes already put together. Is
there some sort of environmental change I need to make for a new application
to use a SQLite database?
I see, the documentation for CursorAdapter states:
The Cursor must include a column named _id or this class will not
work.
The SimpleCursorAdapter is a derived class, so it appears this statement applies. However, the statement is technically wrong and somewhat misleading to a newbie. The result set for the cursor must contain _id, not the cursor itself.
I'm sure this is clear to a DBA because that sort of shorthand documentation is clear to them, but for those newbies, being incomplete in the statement causes confusion. Cursors are like iterators or pointers, they contain nothing but a mechanism for transversing the data, they contain no columns themselves.
The Loaders documentation contains an example where it can be seen that the _id is included in the projection parameter.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_PRESENCE,
Contacts.PHOTO_ID,
Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// ...
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
This has been answered and I would like to make it more comprehensive here.
SimpleCursorAdapter requires that the Cursor's result set must include a column named exactly "_id". Don't haste to change schema if you didn't define the "_id" column in your table.
SQLite automatically added an hidden column called "rowid" for every table. All you need to do is that just select rowid explicitly and alias it as '_id' Ex.
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cur = db.rawQuery( "select rowid _id,* from your_table", null);
Tim Wu's code really works...
If you are using db.query, then it would be like this...
db.query(TABLE_USER, new String[] {
"rowid _id",
FIELD_USERNAME,
},
FIELD_USERNAME + "=" + name,
null,
null,
null,
null);
Yes , I also change the SELECT string query to fix this issue.
String query = "SELECT t.*,t.id as _id FROM table t ";
What solved my issue with this error was that I had not included the _id column in my DB query. Adding that solved my problem.
This probably isn't relevant anymore, but I just hit the same problem today. Turns out column names are case sensitive. I had an _ID column, but Android expects an _id column.
If you read the docs on sqlite, creating any column of type INTEGER PRIMARY KEY will internally alias the ROWID, so it isn't worth the trouble of adding an alias in every SELECT, deviating from any common utilities that might take advantage of something like an enum of columns defining the table.
http://www.sqlite.org/autoinc.html
It is also more straightforward to use this as the ROWID instead of the AUTOINCREMENT option which can cause _ID can deviate from the ROWID. By tying _ID to ROWID it means that the primary key is returned from insert/insertOrThrow; if you are writing a ContentProvider you can use this key in the returned Uri.
Another way of dealing with the lack of an _id column in the table is to write a subclass of CursorWrapper which adds an _id column if necessary.
This has the advantage of not requiring any changes to tables or queries.
I have written such a class, and if it's of any interest it can be found at https://github.com/cmgharris/WithIdCursorWrapper
I've had a look around and found a few similar cases but none where there is a need for specificity in the entries to sum. So here I am.
I have a method filterPayments that returns all entries in my PayTable based on a specific GroupID and is then displayed in my GridView. From there I want to sum the values of 2 of the 5 columns in PayTable, specifically my Interest and Due columns. I'm not sure how to do this in a query, let alone do it only for specific columns.
Question
How do I add the values of all entries in a specific column.
Is it possible to do this in a SQLite query? If so how do I use the returned value of filterPayments and perform the summation only on specific columns? If it isn't then how can I do this?
Below are my code snippets.
filterPayments
Cursor filterPayments(String Payment) {
SQLiteDatabase db = this.getWritableDatabase();
String[] columns = new String[]{"_id", colGroupID, colPayBal, colInterest, colDue, colDateDue, colPaid};
Cursor c = db.query(viewPmnts, columns, colGroupID + "=?", new String[]{Payment}, null, null, null);
return c;
}
GridView
public void Paygrid() {
dbHelper = new DatabaseHelper(this);
String Payment = String.valueOf(txt.getText());
Cursor a = dbHelper.filterPayments(Payment);
startManagingCursor(a);
String[] from = new String[]{DatabaseHelper.colPayBal, DatabaseHelper.colInterest, DatabaseHelper.colDue, DatabaseHelper.colDateDue, DatabaseHelper.colPaid};
int[] to = new int[]{R.id.Amount, R.id.Interest, R.id.Due, R.id.DateDue, R.id.Paid};
SimpleCursorAdapter saa = new SimpleCursorAdapter(this, R.layout.paygrid, a, from, to);
intgrid.setAdapter(saa);
}
I suggest pulling all the data from column and then sum them in Java or android. That would be the simplest way.
There are no core sqlite functions that does it.
https://www.sqlite.org/lang_corefunc.html
You can however create custom sqlite functions. Look below.
How to create custom functions in SQLite
I hope I get your question right. But if you have two columns with the column names interest and due you can get the sum of both columns with the SQL query
SELECT interest + due FROM PayTable;
This also applies for multiplication (and its inverse counterparts). Unfortunately it gets more tricky for non-integer exponentiation (like square root). As far as I know, you need the already mentioned own SQLite function. If you are lucky you can load a module wrapping the math.h from the C standard lib (search for extension-functions.c)
For other ways of summing in tables look at this question for PostgreSQL (It's the same for SQLite)
Somehow while debugging a little Location based android app I get a strange exception. Have a look and share your ideas:
I have connected a ListActivity with an sqlite3 database through a ContentProvider. Now always when I start the ListActivity the program dies with an Exception telling me
column '_id' does not exist
(without a table name) for the line where I create the SimpleCursorAdapter object for my ListActivity.
Cursor cursor = managedQuery(intent.getData(), new String[] {TrackTable.START_LOC, TrackTable.END_LOC}, null, null,
TrackTable.DEFAULT_SORT_ORDER);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.gps_track_entry, cursor, new String[] {
TrackTable.COLUMN_NAME_TIME_START,
TrackTable.COLUMN_NAME_TIME_END
}, new int[] { R.id.l_start, R.id.l_end });
My database looks like that:
sqlite> .tables
.tables
android_metadata ocation track
sqlite> . schema track
.schema track
CREATE TABLE track (
_id INTEGER PRIMARY KEY,
start_location INTEGER,
end_location INTEGER,
start_time TEXT,
end_time TEXT
);
sqlite> .schema location
.schema location
CREATE TABLE location (
_id INTEGER PRIMARY KEY,
long TEXT,
lat TEXT,
alt TEXT,
accu TEXT,
bear TEXT,
sped TEXT,
time TEXT);
sqlite> .schema android_metadata
.schema android_metadata
CREATE TABLE android_metadata (locale TEXT);
I mean, it is quite unlikely that the mistake is an Android bug, but it definitely looks like one, because the only table without an _id is the android_metadata. But maybe I wrote something in a strange way, that the VM now thinks I want to use android_metadata and not track, which I actually want to use.
Erich is right above; the problem is that your SELECT query needs to include BaseColumns._ID as part of the projection. Something like:
Cursor cursor = getContentResolver().query(TrackTable.CONTENT_URI,
new String[] { TrackTable._ID, TrackTable.COLUMN_NAME_TIME_START,
TrackTable.COLUMN_NAME_TIME_END }, null, null, null);
BTW, see the javadoc for CursorAdapter:
The Cursor must include a column named "_id" or this class will not work.
I'm having trouble with something that works in the Notepad example.
Here's the code from the NotepadCodeLab/Notepadv1Solution:
String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);
This code seems to work fine. But just to be clear, I ran the ADB
utility and run SQLite 3. I inspected the schema as follows:
sqlite> .schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE notes (_id integer primary key autoincrement, title text
not null, body text not null);
All seems good to me.
Now on to my application, which, as far as I can see, is basically the same with
a few minor changes. I've simplified and simplified my code, but the
problem persists.
String[] from = new String[] { "x" };
int[] to = new int[] { R.id.x };
SimpleCursorAdapter adapter = null;
try
{
adapter = new SimpleCursorAdapter(this, R.layout.circle_row, cursor, from, to);
}
catch (RuntimeException e)
{
Log.e("Circle", e.toString(), e);
}
When I run my application, I get a RuntimeException and the following prints
in LogCat from my Log.e() statement:
LogCat Message:
java.lang.IllegalArgumentException: column '_id' does not exist
So, back to SQLite 3 to see what's different about my schema:
sqlite> .schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE circles (_id integer primary key autoincrement, sequence
integer, radius real, x real, y real);
I don't see how I'm missing the '_id'.
What have I done wrong?
One thing that's different between my application and the Notepad example is
that I started by creating my application from scratch using the
Eclipse wizard while the sample application comes already put together. Is
there some sort of environmental change I need to make for a new application
to use a SQLite database?
I see, the documentation for CursorAdapter states:
The Cursor must include a column named _id or this class will not
work.
The SimpleCursorAdapter is a derived class, so it appears this statement applies. However, the statement is technically wrong and somewhat misleading to a newbie. The result set for the cursor must contain _id, not the cursor itself.
I'm sure this is clear to a DBA because that sort of shorthand documentation is clear to them, but for those newbies, being incomplete in the statement causes confusion. Cursors are like iterators or pointers, they contain nothing but a mechanism for transversing the data, they contain no columns themselves.
The Loaders documentation contains an example where it can be seen that the _id is included in the projection parameter.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_PRESENCE,
Contacts.PHOTO_ID,
Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// ...
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
This has been answered and I would like to make it more comprehensive here.
SimpleCursorAdapter requires that the Cursor's result set must include a column named exactly "_id". Don't haste to change schema if you didn't define the "_id" column in your table.
SQLite automatically added an hidden column called "rowid" for every table. All you need to do is that just select rowid explicitly and alias it as '_id' Ex.
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cur = db.rawQuery( "select rowid _id,* from your_table", null);
Tim Wu's code really works...
If you are using db.query, then it would be like this...
db.query(TABLE_USER, new String[] {
"rowid _id",
FIELD_USERNAME,
},
FIELD_USERNAME + "=" + name,
null,
null,
null,
null);
Yes , I also change the SELECT string query to fix this issue.
String query = "SELECT t.*,t.id as _id FROM table t ";
What solved my issue with this error was that I had not included the _id column in my DB query. Adding that solved my problem.
This probably isn't relevant anymore, but I just hit the same problem today. Turns out column names are case sensitive. I had an _ID column, but Android expects an _id column.
If you read the docs on sqlite, creating any column of type INTEGER PRIMARY KEY will internally alias the ROWID, so it isn't worth the trouble of adding an alias in every SELECT, deviating from any common utilities that might take advantage of something like an enum of columns defining the table.
http://www.sqlite.org/autoinc.html
It is also more straightforward to use this as the ROWID instead of the AUTOINCREMENT option which can cause _ID can deviate from the ROWID. By tying _ID to ROWID it means that the primary key is returned from insert/insertOrThrow; if you are writing a ContentProvider you can use this key in the returned Uri.
Another way of dealing with the lack of an _id column in the table is to write a subclass of CursorWrapper which adds an _id column if necessary.
This has the advantage of not requiring any changes to tables or queries.
I have written such a class, and if it's of any interest it can be found at https://github.com/cmgharris/WithIdCursorWrapper
How do I get the row ID from a Cursor?
I don't think the Cursor exposes this directly.
SQLiteDatabase.insert() returns the row id of the newly inserted row. Or in Android the convention is that there is a column named "_id" that contains the primary autoincrement key of the table. So cursor.getLong(cursor.getColumnIndex("_id")) would retrieve this.
I had this same problem where the column index for the primary key was reported as -1 (meaning it isn't there). The problem was that I forgot to include the _ID column in the initial SELECT clause that created the cursor. Once I made sure it was included, the column was accessible just like any of the others.
Concerning the last sentence of Nic Strong's answer,following command didn't work for me. cursor.getColumnIndex("_id") was still -1
cursor.getLong(cursor.getColumnIndex("_id"))
Maybe there's some other issue in my configuration that's causing the problem?
Personally I've taken to maintaining my own custom unique id column in each table I create; A pain, but it gets around this issue.
return sqlite_db.query(table, new String[] { "rowid", "*" }, where, args, null, null, null);
In my case I have "rowid" in DataManager.FIELD_ID and this is SQLite identity column (each table in sqlite has this special kind of column), so I don't need any of my own custom unique id column in tables.
Cursor cursor = mySQLiteHelper.getReadableDatabase().query(TABLE_NAME, new String[] { "ROWID", "*" }, where, null, null, null, null);
then
long rowId = cursor.getLong(0);
As long as the TABLE is not defined using WITHOUT ROWID you can get the ROWID (or should that be rowid see below for case) if you specify it as a column to be retrieved.
For example for a table with 3 defined columns (Names, Colour and Age) with no conventional _id column. The following rawQuery works and returns the ROWID :-
Cursor csr = db.rawQuery("SELECT Names, Colour, Age, ROWID FROM " + TABLE_NAME,null);
Note! that the column name in the cursor is lowercase as per :-
Note! ROWID in the SELECT SQL is case independent (e.g. RoWiD works).
Using
Cursor csr = db.rawQuery("SELECT * FROM " + TABLE_NAME,null);
WILL NOT return the ROWID (likewise for null for the columns when using the query method).
Using query (as opposed to rawQuery) works in the same way, that is you need to specifiy ROWID (note alternatives to ROWID below) as a column to be retrieved e.g. :-
Cursor csr = db.query(TABLE_NAME,new String[]{
"OiD",
"Names",
"Colour",
"Age"
},null,null,null,null,null);
Alternatives to ROWID
Instead of ROWID, you can also use _ROWID_ or OID (case independent) as the column name in the query noting that the column name in the resultant cursor is rowid i.e. it is lowercase.