And for a bigger APP project I need to work with an SQLite database. If my code works I don't get any data back. And I think I just don't understand the cursor object. In this code I simply want to get a firstname back but it sasy that my cursor is not initialized correctly, but I got the basic code from Android developers. So I can't figure out why it doesn't work.
public String getVorname (String nachname) {
SQLiteDatabase db = this.getReadableDatabase();
String[] projection = {ListeNamen.VORNAME};
String selection =ListeNamen.NACHNAME+" = ?";
String[] selectionArgs ={nachname};
String sortOrder = ListeNamen._ID + " DESC";
Cursor cursor = db.query(ListeNamen.TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);
cursor.moveToFirst();
String vorname =cursor.getString(cursor.getColumnIndex(ListeNamen.NACHNAME));
cursor.close();
return vorname;
}
I would get back "Jan" as a String but it shows me this Error
java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetString(Native Method)
at android.database.CursorWindow.getString(CursorWindow.java:438)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
at com.example.mainaplikation.DBHelper.getVorname(DBHelper.java:58)
at com.example.mainaplikation.MainActivity$1.onClick(MainActivity.java:29)
With this:
String[] projection = {ListeNamen.VORNAME};
you define the columns that you want the query to select.
So you want only the column ListeNamen.VORNAME.
But with this:
String vorname =cursor.getString(cursor.getColumnIndex(ListeNamen.NACHNAME));
you try to retrieve the column ListeNamen.NACHNAME which does not exist in the results.
By the name of the variable vorname I guess you want to do:
String vorname =cursor.getString(cursor.getColumnIndex(ListeNamen.VORNAME));
but since there is only 1 column in the results, you could also do:
String vorname =cursor.getString(0);
Related
I'm trying to use rawQuery to return a cursor with a few different rows of data to be passed into it. When there is only 1 argument it works. When there is more than 1 argument it displays the empty ListView state. I believe the issue lies here:
// Query for items from the database and get a cursor back. Edited code for clarity:
recipeCursor = db.rawQuery("SELECT course, name, _id " +
" FROM recipes WHERE _id = ?",
selectedRecipesSQL);
When the code works the selectedRecipesSQL would look something like:
String[] selectedRecipesSQL;
selectedRecipesSQL = new String[]{"2"};
And when it doesn't work it would be something like
String[] selectedRecipesSQL;
selectedRecipesSQL = new String[]{"2 OR 5"};
So, to be clear, I can display a single row of the table in my ListView, but if I try to display more than one row of the table then it won't display anything.
One ugly solution which has crossed my mind (but I haven't pursued) is that I need to edit the rawQuery selection statement to read something like:
recipeCursor = db.rawQuery("SELECT course, name, _id " +
" FROM recipes WHERE _id = ? OR _id = ? OR _id = ?",
selectedRecipesSQL);
I'd probably use a for loop to generate the correct amount of WHERE "_id = ?" and then use a string array:
selectedRecipesSQL = new String[]{"2", "5"};
One way of doing it is by passing the possible values of _id as 1 string which is a comma separated list like this:
selectedRecipesSQL = new String[]{"1,2,3"};
and in your query use the operator LIKE:
recipeCursor = db.rawQuery(
"SELECT course, name, _id FROM recipes WHERE ',' || ? || ',' LIKE '%,' || _id || ',%'",
selectedRecipesSQL
);
This works also for just 1 value.
static String multiply__concat_string(String text,String joiner_,int multiple_)
{
String output="";
for(int i=0;i<multiple_;i++)
{
output+=(text+joiner_);
}
if(output.length()>0)
{
output=output.substring(0,output.length()-1);
}
return output;
}
Use it like this :
selectedRecipesSQL = new String[]{"2", "5"};
db.rawQuery("SELECT course, name, _id " +
" FROM recipes WHERE _id IN("+multiply_concat_string("?",",",selectedRecipesSQL.length)+")",
selectedRecipesSQL);
I'm writing a basic android app in which personal information like name, email, etc. is filled in and stored in an SQLite database by pressing a "submit"-button (this all works perfectly). Then there's a search button which should search for a corresponding person in the database when one field is filled in (e.g. only the field name is given a string "harry" and the other fields keep a null-value). This is the corresponding code in my DatabaseHelper class:
public Person getPerson(String naam, String adres, String email, String geslacht,
String leeftijd, String geboortedatum){
Log.i("Main activity","Person to find: "+naam);
SQLiteDatabase db= this.getReadableDatabase();
Cursor curs=db.rawQuery("SELECT name FROM personen WHERE (name = ?) OR (adress = ?) "
+ "OR (email = ?) OR (gender = ?) OR (age = ?) OR (birthday = ?)",
new String[]{naam, adres, email, geslacht, leeftijd, geboortedatum});
Log.i("Main activity", "Query works");
I used the logs to make sure where the error is thrown and found that the rawQuery does work when all the args[] fields are given a value, but gives an error when one field (e.g. email) contains a null value. Isn't this why I should use the OR statement instead of the AND statement? If not, how can I make it work when not all fields are filled in in the app?
A fast fix should be to do something like that:
new String[]{naam == null? "''":naam, etc}
Check if your sting is initialized, if it is not, replace it by a dummy value.
rawQuery() expects a string array, but null is not a valid string.
You'd have to put the NULL directly into the SQL string, without a parameter.
But when you're constructing the string dynamically anyway, you can just as well leave out that comparison.
search by name:
// Getting single contact
Contact getContact(String name) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_CONTACTS, new String[] { KEY_ID,
KEY_NAME, KEY_PH_NUM }, KEY_NAME + "=?",
new String[] { name }, null, null, null, null);
//...
for access:
Contact contact = null;
if (cursor.moveToFirst()) {
contact = new Contact(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2));
}
cursor.close();
// can return null if no contact was found.
return contact;
I have a sqlitedatabase I'm implementing within my app and I keep receiving an IllegalStateException when launching.
09-21 22:48:26.749 15762-16277/nz.co.exium.panther E/AndroidRuntime﹕ FATAL EXCEPTION: SyncAdapterThread-2
java.lang.IllegalStateException: Couldn't read row 0, col 4 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetString(Native Method)
at android.database.CursorWindow.getString(CursorWindow.java:438)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
at android.database.CursorWrapper.getString(CursorWrapper.java:114)
at nz.co.exium.panther.sync.PantherSyncAdapter.getRegistrationId(PantherSyncAdapter.java:269)
at nz.co.exium.panther.sync.PantherSyncAdapter.onPerformSync(PantherSyncAdapter.java:64)
at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:254)
I believe this is caused by the query returning a fairly empty table (except for _ID that is autoincremented) and then when I attempt to get a String from the cursor.
String registrationID = "";
Uri uri = CustomerEntry.CONTENT_URI;
Cursor cursor = mContext.getContentResolver().query(uri, CUSTOMER_PROJECTION, null, null, null);
if (cursor.moveToFirst()) {
registrationID = cursor.getString(INDEX_CUST_REGID);
}
SQL create table call:
final String SQL_CREATE_CUSTOMER_TABLE = "CREATE TABLE " + CustomerEntry.TABLE_NAME + " (" +
CustomerEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
CustomerEntry.COLUMN_CUST_NAME + " TEXT NOT NULL, " +
CustomerEntry.COLUMN_CUST_EMAIL + " TEXT NOT NULL, " +
CustomerEntry.COLUMN_CUST_QRHASH + " TEXT NOT NULL," +
CustomerEntry.COLUMN_CUST_REGID + " TEXT NOT NULL)";
In this case, the INDEX_CUST_REGID is a final static int related to the position in the String[] projection, 3rd position in this case. It makes sense this would throw but is there a method or way to query the SyncAdapter for a specific column like the CUST_REGID or a method to check if the Column requested was returned before attempting a cursor.getString()?
This also might solve another problem I have with saving the Reg ID before knowing the EMAIL, NAME, QRHASH. Can't insert just one column without the rest having a value as well (NOT NULL), even though it would be worthless data and overwritten asap.
Method attempting to store Reg ID.
private void storeRegistrationID(Context context, String regID) {
//DB insert regid
ContentValues cValues = new ContentValues();
cValues.put(CustomerEntry.COLUMN_CUST_NAME, "");
cValues.put(CustomerEntry.COLUMN_CUST_EMAIL, "");
cValues.put(CustomerEntry.COLUMN_CUST_QRHASH, "");
cValues.put(CustomerEntry.COLUMN_CUST_REGID, regID);
mContext.getContentResolver().insert(CustomerEntry.CONTENT_URI, cValues);
}
projection as requested:
String[] CUSTOMER_PROJECTION = new String[]{
CustomerEntry._ID,
CustomerEntry.COLUMN_CUST_NAME,
CustomerEntry.COLUMN_CUST_EMAIL,
CustomerEntry.COLUMN_CUST_QRHASH,
CustomerEntry.COLUMN_CUST_REGID
};
Are you certain the table was actually created? There's a semi-colon mising from the end of your SQL_CREATE_CUSTOMER_TABLE text string - although I'm not sure if it is mandatory to run the sql for creating the table. I would suggest running it on the Eclipse emulator, then from the DDMS perspective, take a copy of the database somewhere where you can open it with the SQLite Manager plugin for Firefox - this will show you the database tables.
I'm storing a number of objects for my app in an SQLite Database. The class for these objects has a constructor that takes a Cursor object, passed in from the Database class. Example:
public MyClass(Cursor cursor) {
this.id = cursor.getString(cursor.getColumnIndex(MyDatabase.KEY_ROWID));
this.nickname = cursor.getString(cursor.getColumnIndex(MyDatabase.KEY_NICKNAME));
...and so on.
However I've noticed that at random times I've been getting a crash when getColumnIndex for the ID column returns -16. (And if I comment out that line, whichever the first column I try to access is, it will also return -16). I've added some extra logging around it but it hasn't helped as it seems like the columns are fine:
public MyClass(Cursor cursor) {
Log.i("TEST", Column names are: " + Arrays.toString(cursor.getColumnNames()));
Log.i("TEST", Making object, id column index is " + cursor.getColumnIndex(MyDatabase.KEY_ROWID));
Which prints:
Column names are: [_id, nickname...]
Making object, id column index is -16
So it sees like everything should be fine, anyone got any clue why everything could be getting so messed up while reading from the Cursor?
EDIT: Here's how I'm getting the cursor, this is a method in the database class:
public MyObject getMyObject(String id) {
MyObject objectFound = null;
String[] whereArgs = { id };
Cursor cursor = db.query(true, getTableName(), null, WHERE_EQUALS, whereArgs, null, null, null, null);
if(cursor.moveToFirst()) {
//Should only return 1 entry from DB
while(cursor.isAfterLast() == false) {
objectFound = new MyObject(cursor);
cursor.moveToNext();
}
}
cursor.close();
return objectFound;
}
In my application, I create a table for my database like this :
String action;
action= "CREATE TABLE ";
action+=TABLE_LIEUX;
action+="(Name TEXT NOT NULL PRIMARY KEY);";
base.execSQL(action);
I then add a record to this table with :
ContentValues valeur;
long InsertLine=-10;
valeur=new ContentValues(1);
valeur.put("Name","'"+name+"'");
InsertLine=getWritableDatabase().insert(TABLE_LIEUX,null,valeur);
The value I get for InsertLine is 1, as expected. But when I try to search for the row added with :
result=(SQLiteCursor)getWritableDatabase().query(TABLE_LIEUX,null,"Name='"+name+"'",null,null,null,null);
the SQLiteCursor result I get has a length of -1. And when I try to add the row again, I get an SQLiteException which indicates the row should be unique (so, despite the result of the search, the row is already in the database).
Any idea?
You must force the Cursor to read the returned data (by calling moveToFirst or something like that) before you can get the cursor's record count.
Furthermore, you must not quote values when using the ContentValues put function; the value in the database now contains superfluous quotes.
Why did you cast your query result to (SQLiteCursor)?
Query statements always return a Cursor object so bother with the cast.
Cursor result = getWritableDatabase().
query(TABLE_LIEUX, null, "Name='"+name+
"'", null, null, null, null);
String mString;
if(result != null && c.moveToFirst()) {
mString = result.getString(result.
getColumnIndex("Name"));
}
hope this helps.