How To Test If Cursor Is Empty in a SQLiteDatabase Query - java

I have an SQL table which is created by the following code:
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + _ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + SUBJECT
+ " TEXT NOT NULL," + TOPIC + " TEXT NOT NULL, "
+ LECTURENUMBER + " TEXT NOT NULL, " + PAGENUMBER
+ " TEXT NOT NULL, " + DATE + " TEXT NOT NULL, " + _DATA
+ " TEXT NOT NULL);");
}
I query the table as follows:
String sql = "SELECT " + _ID + "," + SUBJECT + " FROM " + TABLE_NAME
+ " GROUP BY " + SUBJECT + ";";
Cursor cursor = subjects.getReadableDatabase().rawQuery(sql, null);
The problem is I have to start an Activity A if the cursor is empty(i.e. the table is storing no values) and Activity B if the cursor is not empty(i.e. table is filled).
I am unable to find a method which can tell me if the table is empty or not.
I Have tried to used Log as follows:
private void showSubjectsOnList() {
String sql = "SELECT " + _ID + "," + SUBJECT + " FROM " + TABLE_NAME
+ " GROUP BY " + SUBJECT + ";";
Cursor cursor = subjects.getReadableDatabase().rawQuery(sql, null);
Log.d("Events",Integer.toString(cursor.getCount()));
if(cursor.isNull(0)!=false){
cursor.close();
subjects.close();
startActivity(new Intent(this,OpenScreen.class));
}
}
But the LOG shows 1, if the table is empty...and again 1, if table has 1 entry....it shows 2, if table has two entries and so on.
Can you suggest some method of solving my problem of starting different activities based on if cursor is empty or not.

What about testing the cursor like this, and then doing what you've said:
if(cursor!=null && cursor.getCount()>0)
getCount ()
Returns the numbers of rows in the cursor
http://developer.android.com/reference/android/database/Cursor.html#getCount()

The easiest and cleanest way to test for an empty cursor is the following code:
if ( cursor.moveToFirst() ) {
// start activity a
} else {
// start activity b
}
Per the docs, the method returns false if the cursor is empty:
http://developer.android.com/reference/android/database/Cursor.html#moveToFirst%28%29
public abstract boolean moveToFirst ()
Added in API level 1 Move the cursor to the first row.
This method will return false if the cursor is empty.
Returns whether the move succeeded.

You just need to use getCount().
If your sql is correct but doesn't return any row you will have a NOT null cursor object but without a rows and getCount() will return 0.

Deleted records remain in SQLite as null records, but getCount() counts only not null records. If your table has some records that are null, some of not null records will have _Id numbers bigger than result of getCount(). To reach them, you can iterate cursor ( using for() loop ) double the number of times than result of getCount() and use the cursor to fill record_Id numbers into an array. Lets say resulting array is { 1, 2, 5, 6, 7, 8, 9, 11, 12, 14 }.
That means records 3, 4, 10, 13, are null records and your table has 14 record all together, not 10 that you got from getCount().
Remember:
getCount() returns number of not null records ,
cursor returns _Id numbers of not null records,
_Id numbers "missed" by cursor are _Id numbers of null records,
must reach sufficiently further than getCount() to get them all.

My suggestion would be using a ListActivity.
Those are Activity's which are meant to display items in a ListView. You can simply use a SimpleCursorAdapter to populate them (also illustrated in the ListActivitys JavaDoc page).
They also offer a setEmptyView()-method, which can be used to display a View (might be a TextView) which informs the user that there are no records yet and how he can create one.
An example on how to do that can be found here.

I believe your problem is you're not creating a proper query.
You should use the SQLiteDatabase query.
Cursor c = db.query(TABLE_NAME, null,
null, null, null, null, null);
You then can use c.getCount() to determine if the table has anything.

Related

Cannot get the max value in a SQLite database

I am trying to get the max id of a table in SQLite in Android. This is how I get it in the database helper:
public int getMaxIncrementation() {
SQLiteDatabase sqLiteDatabase = this.getReadableDatabase();
String result = "0";
try{
Cursor cursor = sqLiteDatabase.rawQuery("SELECT MAX(id) FROM " +TABLE_INCREMENTATION, new String[]{});
cursor.moveToFirst();
result = cursor.getString(cursor.getColumnIndex(INCREMENTATION_ID));
}catch (Exception ex) {
Log.e("ex", ex.getMessage());
}
return Integer.parseInt(result);
};
This is how I created the table:
private static final String CREATE_TABLE_INCREMENTATION = "CREATE TABLE IF NOT EXISTS " + TABLE_INCREMENTATION
+ "("
+ INCREMENTATION_DATEADDED + " TEXT,"
+ INCREMENTATION_DIRECTION + " INTEGER,"
+ INCREMENTATION_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ INCREMENTATION_USER + " TEXT"
+ ")";
This is the snapshot of my table with data in it:
On debugging, I always get this error:
Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor
is initialized correctly before accessing data from it.
First, since you don't have in the query any ? placeholders then you don't need to pass any parameters to the sql statement, so the 2nd argument of rawQuery() should be null.
Also you must give an alias to the column that your query returns and use it to get the returned value (you can't use INCREMENTATION_ID because it is not the name of the column returned):
Cursor cursor = sqLiteDatabase.rawQuery("SELECT MAX(id) AS maxid FROM " +TABLE_INCREMENTATION, null);
if (cursor.moveToFirst())
result = cursor.getString(cursor.getColumnIndex("maxid"));
Or if you don't use an alias then use 0 as there is only 1 column returned:
Cursor cursor = sqLiteDatabase.rawQuery("SELECT MAX(id) FROM " +TABLE_INCREMENTATION, null);
if (cursor.moveToFirst())
result = cursor.getString(0);

SQLite cannot find column

I'm creating my first android app and I'm having difficulties using sqlite. I'm using the following code to create my table. It works fine for the 3 first columns (_ID, COL_TITLE and COL_MAX) but I can't seem to create the last column.
String createTable = "CREATE TABLE " + TaskContract.Entry.TABLE + " (" +
TaskContract.Entry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
TaskContract.Entry.COL_TITLE + " TEXT NOT NULL, " +
TaskContract.Entry.COL_MAX + " REAL, " +
TaskContract.Entry.COL_INCREMENT + " REAL " +
");";
I tried getting the column index like this:
Cursor cursor = db.query(TaskContract.Entry.TABLE,
new String[]{TaskContract.Entry._ID,
TaskContract.Entry.COL_TITLE,
TaskContract.Entry.COL_MAX},
TaskContract.Entry._ID + " = ?",
new String[]{String.valueOf(id)},
null, null, null);
int idx_id = cursor.getColumnIndex(TaskContract.Entry._ID); //returns 0
int idx_title = cursor.getColumnIndex(TaskContract.Entry.COL_TITLE); //returns 1
int idx_max = cursor.getColumnIndex(TaskContract.Entry.COL_MAX); //returns 2
int idx_inc = cursor.getColumnIndex(TaskContract.Entry.COL_INCREMENT); //returns -1
As you can see getColumnIndex returns -1 for COL_INCREMENT
I also tried reading the data like this:
cursor.getString(3)
Looks as if the table only contains 3 column and I don't know where I went wrong. I've tried updating database version and uninstalling the app.
You need to pass TaskContract.Entry.COL_INCREMENT in your query too. Its missing out currently in your query.
Cursor cursor = db.query(TaskContract.Entry.TABLE,
new String[]{TaskContract.Entry._ID,
TaskContract.Entry.COL_TITLE,
TaskContract.Entry.COL_MAX,
TaskContract.Entry.COL_INCREMENT},
TaskContract.Entry._ID + " = ?",
new String[]{String.valueOf(id)},
null, null, null);

how to get every row from SQLite from a function that returns only one row at a time

I have a SQLite DB which contains N rows, I need to retrieve every row by knowing the number of rows in the DB, what I've tried is this:
public CategoriesItem returnCategory(int index){
SQLiteDatabase db = this.getWritableDatabase();
Cursor mRow= db.rawQuery("select * from " + TABLE_CATEGORY + " LIMIT 0, " + index, null);
if (null!=mRow) {
mRow.moveToNext();
item.auto_id = Integer.toString(mRow.getInt(mRow.getColumnIndex(KEY_ID)));
item.title = mRow.getString(mRow.getColumnIndex(KEY_CATEGORY_NAME));
item.subTitle = mRow.getString(mRow.getColumnIndex(KEY_CATEGORY_DESCRIPTION));
}
return item;
}
The problem is that it returns only the first row, everytime even if the index is not 1.
What is wrong with the query? How can I get a single row values by knowing the amount of rows in the DB?
This seem to work, I'll do some test but this should be the solution:
Cursor mRow= db.rawQuery("select * from " + TABLE_CATEGORY + " LIMIT 1 OFFSET " + index, null);
What you probably want to do is iterate over the Cursor, you can then use the data from every single row.
What's the best way to iterate an Android Cursor?

Slow retrieval of data in SQLITE takes a long using ContentProvider

I have an application in Android (running 4.0.3) that stores a lot of data in Table A. Table A resides in SQLite Database. I am using a ContentProvider as an abstraction layer above the database.
Lots of data here means almost 80,000 records per month. Table A is structured like this:
String SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_A + " ( " +
COLUMN_ID + " INTEGER PRIMARY KEY NOT NULL" + "," +
COLUMN_GROUPNO + " INTEGER NOT NULL DEFAULT(0)" + "," +
COLUMN_TIMESTAMP + " DATETIME UNIQUE NOT NULL" + "," +
COLUMN_TAG + " TEXT" + "," +
COLUMN_VALUE + " REAL NOT NULL" + "," +
COLUMN_DEVICEID + " TEXT NOT NULL" + "," +
COLUMN_NEW + " NUMERIC NOT NULL DEFAULT(1)" + " )";
Here is the index statement:
String SQL_CREATE_INDEX_TIMESTAMP = "CREATE INDEX IF NOT EXISTS " + TABLE_A +
"_" + COLUMN_TIMESTAMP + " ON " + TABLE_A + " (" +
COLUMN_TIMESTAMP + ") ";
I have defined the columns as well as the table name as String Constants.
I am already experiencing significant slow down when retrieving this data from Table A. The problem is that when I retrieve data from this table, I first put it in an ArrayList and then I display it. Obviously, this is possibly the wrong way of doing things. I am trying to find a better way to approach this problem using a ContentProvider. But this is not the problem that bothers me.
The problem is for some reason, it takes a lot longer to retrieve data from other tables which have only upto 12 records maximum. I see this delay increase as the number of records in Table A increase. This does not make any sense. I can understand the delay if I retrieve data from Table A, but why the delay in retrieving data from other tables.
To clarify, I do not experience this delay if Table A is empty or has less than 3000 records.
What could be the problem?
EDIT: 09/14/2012 9:53 AM
To clarify, I am using a ContentProvider to manage the database. To query the data, I am using the context.getContentResolver().query method.
My query code in the ContentProvider:
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
final SQLiteDatabase db = dbHelper.getReadableDatabase();
String tableName = getTableName(uri);
queryBuilder.setTables(tableName);
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
So this is embarrassing:
Apparently, there was one line of code somewhere during the Application Load that was retrieving data from Table A. That was what was slowing down the application as a whole.
In any case, I still have to figure out how to optimize loading data from Table A using a ContentProvider.

Why is a decimal place being removed when I insert data? SQLite (Android Development)

I am attempting to enter values such as "0.20" within a table but when I display it within an activity it shows "0.2". I am uncertain as to why the '0' is being removed i.e. incorrect structure of the table, insertion, or being returned.
My table is created as followed:
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_NAME
+ " TEXT NOT NULL, " + KEY_SWIMMERLAPS + " INT NOT NULL, "
+ KEY_SPONSOR + " DEC(4,2) NOT NULL );");
I then insert the data:
public long addSwimmer(String name, String laps, String sponsor) {
int i = Integer.parseInt(laps);
ContentValues cv = new ContentValues();
cv.put(KEY_NAME, name);
cv.put(KEY_SWIMMERLAPS, i);
cv.put(KEY_SPONSOR, (new DecimalFormat("0.00##")).format(0.20));
return ourDatabase.insert(DATABASE_TABLE, null, cv);
}
and then return the sponsorship data:
public String getSwimmerSponsors() {
String[] columns = new String[] { KEY_SPONSOR };
Cursor c = ourDatabase.query(DATABASE_TABLE, columns, null, null, null,
null, KEY_SWIMMERLAPS + " DESC");
String result = "";
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
result = result + c.getString(0) + "\n";
}
return result;
}
Edit - I display the returned result in my layout as follows:
String sponsors = swimmerDb.getSwimmerSponsors();
tvSponsor.setText(sponsors);
Thanks.
Because you're displaying an unformatted Java variable, and leading/trailing 0s are suppressed.
If you want to format it with a specific layout, use one of the printf/format variants:
printf("%.2f", num); // Etc.
When talking numbers 0.20 and 0.2 are exactly the same. If you want to keep the formatting than I suggest you insert the value as a formatted string.
cv.put(KEY_SPONSOR,0.20);
turns into
cv.put(KEY_SPONSOR, (new DecimalFormat("0.00##")).format(0.20));
EDIT: If you go this way, don't forget to change the KEY_SPONSOR column type from DEC to TEXT
SQLite does not offer DECIMAL or any similar type where you can specify the precision. The only data type with decimal places is REAL and that is how your number is being handled.
If you need specified precision you can multiply (by 100, in this case) and store as INTEGER, or use a TEXT column.

Categories

Resources