Column '_id' does not exist SimpleCursorAdapter revisited - android

I want to use the SimpleCursorAdapter to fill in my ListActivity, but I'm getting the classic exception because there is no '_id' field in my Cursor. Unfortunately, this type of query does not provide me with a field that I can use as my _id field being of the form:
SELECT DISTINCT room from tblRates WHERE resid='ABC' AND date='2011-10-17'
Because of the DISTINCT I can't just add in the _id. So what do I do short of setting up a custom Adapter?
Btw, I have seen this post already so I do understand why I'm getting the error. Just wondering how to get an _id in there with the type of query I'm doing:
Android column '_id' does not exist?

You could do something like this...
SELECT DISTINCT room, 1 _id from tblRates WHERE resid='ABC' AND date='2011-10-17'
This will add an _id column with a value of 1 for each row. Also I think sqlite has something like a hidden "rowid" column for each table if you want distinct values for the column instead of a 1.

So what do I do short of setting up a custom Adapter?
Besides the custom Adapter approach, you could use CursorWrapper to add your own _id values. Just sequentially number them starting from 1 or something, and don't attempt to use them as actual keys in your database. :-)
UPDATE
Off the cuff...
Step #1: Create a subclass of CursorWrapper.
Step #2: Hang onto the getColumnCount() value of the wrapped Cursor, here referred to as N.
Step #3: Override getColumnCount() to return N+1.
Step #3: Override getColumnIndex() to return N as the _id column index.
Step #4: Override all other methods that take int columnIndex as a parameter. If the index is not N, delegate the work to the wrapped Cursor; otherwise, implement it yourself (or throw a RuntimeException if it is impossible or inconvenient and you don't need it). For getInt() and getLong() implementations (not sure which CursorAdapter uses), return some likely unique value (e.g., just use your position via getPosition()).
Step #5: Create an instance of your subclass, wrapping your Cursor with the DISTINCT clause, and hand that to the CursorAdapter.

Using method "query" in SQLiteDatabase may help.
For example,
SQLiteDatabase db = openHelper.getReadableDatabase();
Cursor c = db.query(
"tblRates",
new String[] { "_id", "room" },
"resid=? AND date=?",
new String[] { "ABC", "2010-10-17" },
"room",
null,
"room");
SimpleCursorAdapter a = new SimpleCursorAdapter(
getActivity(),
android.R.layout.simple_dropdown_item_1line,
c,
new String[] { "room" },
new int[] { android.R.id.text1 },
0);

Related

Listview not listing Database values using CursorAdaptor [duplicate]

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

simple cursor adapter column '_id' does not exist

I have _id set up in the database but when debugging it says the _id does not exist at this line:
SimpleCursorAdapter sqldb_adapter = new SimpleCursorAdapter(this, Resource.Layout.Recordslayout, sqldb_cursor, from, to);
I am using the tutorial from this blog.
One thing I do not have it set up in my mainactivity but a different one. I have set the public class to the correct activity.
This occurs when you don't have the _id column present in the projection(String[] from in your case). Adapter needs this column. Crosscheck that _id column is present and add some code if you want further help.

Using SimpleCursorAdapter got IllegalArgumentException

I got a SQLite database and I would like to display data in a listView, I try it with a SimpleCursorAdapter:
contactAdapter = new SimpleCursorAdapter(this, R.layout.contact_row, cursor,
new String[] { MyDb.ACCOUNT_NAME },
new int[] { R.id.contactNameTv });
On this very line I get an
IllegalArgumentException: column '_id' does not exists.
Well, thanks JVM I just don't see what the heck should I do with that, because I don't even use _id column and this statement also wrong because I exported the database and opened with sqlite database opener and I can see the column _id in the database so it does exist.
Can somebody tell me when this error should appear and what is it trying to tell me ?
E D I T:
njzk2 pointed me right, I wasn't queried the "_id" column in my cursor getting func. Thanks.
App Crashes On Startup Due To java.lang.IllegalArgumentException: column '_id' does not exist
see the above sample which has same issue like this may be it will help you
Solution
You should add "_id" field when you create your table.
//example
"CREATE TABLE TABLE_NAME (_id INTEGER PRIMARY KEY AUTOINCREMENT,field1 TEXT, field2 TEXT, etc TEXT)";
The Cursor must include a column named "_id" or this class will not work.
Additionally, using {#link android.database.MergeCursor} with this class will not work if the merged Cursors have overlapping values in their "_id"
columns.
Warning!!
SimpleCursorAdapter this constructor was deprecated in API level 11. This option is discouraged, as it results in Cursor queries being performed on the application's UI thread and thus can cause poor responsiveness or even Application Not Responding errors. As an alternative, use LoaderManager with a CursorLoader.
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
An alternative is to use CursorAdapter and CursorLoader.
CursorAdapter is very useful when you work with databases for example if you want to show a list of data in ListView, GridView or RecyclerView directly from a database.
CursorLoader runs an asynchronous query in the background!
http://developer.android.com/reference/android/content/CursorLoader.html
I hope it helps you!!
cheers.

Android column '_id' does not exist?

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

Displaying results of a SQL join in a ListActivity

I need to display results from a SQL join in a ListView/ListActivity.
I've created a cursor:
Cursor cursor = db.rawQuery(LIST_JOIN_SQL, null);
and if I iterate through the cursor, the results are exactly what I expect. However when I try and use a SimpleCursorAdapter to display these results in a ListView I get a runtime exception because there is no column called ' id'.
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.item, cursor, FROM, TO);
Where FROM and TO are defined as:
private static String[] FROM = { "name", };
private static int[] TO = { R.id.name, };
Now I figure I'm probably using the wrong approach here, as it seems SimpleCursorAdapters aren't meant for displaying results of joins.
What approach would you recommend here? I'm restricted to using Android 1.6 APIs.
Try selecting one of your columns as _ID alias
select col1 as _id from table
To use CursorAdapter (or any of its subclasses) you're required to have the "_id" column; it's explicitly stated in the documentation. That's because CursorAdapter uses this column heavily.
What I recommend is whatever you think (based on your project) to be the easier of these two paths:
Create an _id field in one of the tables so that when you join, you end up with an _id field.
Implement your own ListAdapter (starting from BaseAdapter) that is essentially a CursorAdapter but doesn't require an _id field.
I suspect #1 would be easier to do if you control the database, but that you'd have to do #2 if you cannot change the databases' schema.

Categories

Resources