Does cursor copy the result set? - android

For example, if i use following code to query some data from database.
Uri uri = Uri.parse("content://com.android.contacts/contacts?address_book_index_extras=true");
String selection = "LEFT OUTER JOIN (select raw_contact_id, data1 from data where mimetype_id = 5) AS phone_data ON(_id = phone_data.raw_contact_id)";
Cursor c = getContentResolver().query(Contacts.CONTENT_URI, null, selection, null, null);
What i want to ask is after the query method, does database copy its result set to cursor or just make cursor something like a pointer and point to the first line of result set and query for more data when we call `moveToNext'
thanks

Yes. It is a readonly copy of the DB.

From Android Developers:
This interface provides random read-write access to the result set returned by a database query. Cursor implementations are not required to be synchronized so code using a Cursor from multiple threads should perform its own synchronization when using the Cursor.

Related

Android - Efficient way using the Database Cursor

I've implemented a sqlite database in my application and I'm using the Android Cursor. I've written a database class with e.g. the database name and the table and column names. Here I also have various methods, like the following:
public Cursor getCorrectQuestions(int topic) {
SQLiteDatabase db = getReadableDatabase();
Cursor questionCursor = db.rawQuery(
"Select * FROM Result, Question WHERE Result.qid = Question._id AND correct = 1 AND topic = " + topic,
null);
questionCursor.moveToFirst();
return questionCursor;
}
public Cursor getExamQuestions() {
SQLiteDatabase db = getReadableDatabase();
Cursor questionCursor = db.rawQuery("Select * FROM Question WHERE topic = 7", null);
questionCursor.moveToFirst();
return questionCursor;
}
public Cursor getAnswerItems(String id) {
SQLiteDatabase db = getReadableDatabase();
Cursor answerCursor = db.rawQuery(
"Select * FROM Answer, Question WHERE Question._id = " + id + " AND Question._id = Answer.qid", null);
answerCursor.moveToFirst();
return answerCursor;
}
public Cursor getUserResults(String qid) {
SQLiteDatabase db = getReadableDatabase();
Cursor userResultsCursor = db.rawQuery("SELECT result FROM Result, Answer WHERE Result.qid = " + qid, null);
userResultsCursor.moveToFirst();
return userResultsCursor;
}
In the QuizActivity which has 3 cursors (answerCursor, questionCursor, userResultCursor) I call these methods.
My question is: is it necessary to create a SQLiteDatabase Object in every method or is it possible to define this once in my database constructor? And do I need 3 different cursors in my activity or is there a better way to handle this?
Assuming the methods you have written are part of a SQLiteOpenHelper, you are not really creating 3 database objects. Only the first call to getReadableDatabase() actually creates a database object, and subsequent calls reuse the same object over again.
You also need to make a new Cursor for each query you perform, as they cannot be edited after creation. In this sense, there is no way to simplify what you have already done.
As far as improvements to your code, there are a few things you can look at:
Consider putting your database in a ContentProvider and accessing it via URI's. This will require more upfront work, but will make it much easier if you want to share your database with other apps or sync your data to a server in the future.
Leave the cursor in its default position (don't call moveToFirst()). That way when the caller receives the cursor, it can use the following code to start iterating cursor rows without performing any further checks:
while (cursor.moveToNext()) {
// extract data
}
This is because the cursor returned from a query is initially positioned before the first row of data, so if the cursor is empty then the code inside the while loop simply never executes at all.

Android Sql. Query single coloumn, multiple values

I have database with three columns.
I would like to query the database, based on one column which can have multiple values.
For single parameter we can the normal query method where cardName is String[]
Cursor cursor = database.query(Database.TABLE_COUPON_CARD, allColumns,Database.COLUMN_CARD_NAME + " = ?", cardName, null, null,null);
but if there are more than one value, I get a Android SQLite cannot bind argument exception
For multiple values of the same column we can use IN statement but, here how do I write the QUERY or how should i form the rawQuery
String whereClause = Database.COLUMN_CARD_NAME+ " IN(?)";
Cursor cursor = database.query(Database.TABLE_COUPON_CARD, allColumns,whereClause,new String[][]{cardName}, null, null,null);
Android QUERY doesnot take array of array.
What should the correct query be?
TEMPORARY SOLUTION
Currently I have created a method which dynamically creates the clause.
private static StringBuilder buildInClause(String[] myStringArray){
StringBuilder fullString=new StringBuilder();
fullString.append("(");
for(int i=0;i<myStringArray.length;i++){
fullString.append(" '"+myStringArray[i]+"' ");
if(i!=myStringArray.length-1){
fullString.append(",");
}
}
fullString.append(")");
return fullString;
}
If anyone has any other solution please do share.
For two values: IN(?,?). For three values: IN(?,?,?). Get the idea? Each ? corresponds to a single literal in the selection args array.

How to return all data from one column Android SQL

I have an SQLite Database in my application. It has three columns. being _id, TEXT, and Location. If I want to return all the data from, say, the TEXT column should I use cursor.getColumnIndex(2)? I am obviously new to SQLite. And and all help is appreciated. Thanks everyone!
Yes, friend, you are new.
First off, your database doesn't have three columns, but rather, your table does. Databases have tables, tables of columns (fields) and rows (records).
Secondly, TEXT is not a valid name for a column, as it's a datatype. Let's say you called the three columns id, theText, and location -- then if you selected all three columns to be returned, the second one would be accessible through:
cursor.getString(1); // that's the second column returned
or
cursor.getString(cursor.getColumnIndex( "theText" ) );
However, you can have sqlite do most of the work for you by selecting only the column you're interested in, so then you'd cursor.getString(0) as it's the only column returned.
For more pertinent explanations, please post your code in the question.
simply apply the query of getting all contacts and take an array of string type and then add the required record in that array as shown below
I hope this code help u
in DBHelper getting record of particular column :
public ArrayList<String> getAllCotactsEmail() {
ArrayList<String> arrayList=new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery( "select * from contacts", null );
res.moveToFirst();
if (res != null)
{
while(res.isAfterLast() == false){
arrayList.add(res.getString(res.getColumnIndex(CONTACTS_COLUMN_EMAIL)));
Log.d("emailssinlisttt",arrayList.toString());
res.moveToNext();
}}
return arrayList;
}
retrieve :
email=mydb.getAllCotactsEmail();
Log.d("emaillllll",email.toString());
You need to query your Database to get your data. This query will return a Cursor with the column you specified in the query.
To make query, you need to call query() method from ContentResolver. To get your ContentResolver, you can use getContentResolver() from a Context like Activity :
getContentResolver.query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
To understand all parameters, see : ContentResolver
In your case, you want only TEXT column so pass a String array with your TEXT column name for projection parameters.
You want all rows so your selection and selectionArgs parameters must be null.
If you don't care about order, pass null for sortOrder (rows will be sort by ID) :
Cursor c = getContentResolver.query(yourUri, new String[]{"TEXT"}, null, null, null)
This query will return a cursor, to extract your values from the cursor, make a loop like :
if(c.moveToFirst()) {
do {
final String text = c.getString(c.getColumnIndex("TEXT"));
} while (c.moveToNext());
}
Hope this will help you :)

Quering SqlLite database where clause Android

Hi I am developing an android app.I am trying to query from the database. I need to fetch everything from the table TASK where dbDate = AlarmDate and dbdTime = AlarmTime.
c = db.rawQuery("SELECT * FROM TASK WHERE dbDate = '"+AlarmDate+"' AND dbTime= '"+Alarmtime+"'", null);
The problem is ,the cursor c is null.
I am not sure where I am going wrong in the query. Please Help.
Thanks!
Android has binding method to avoid sql inject. You can use the second parameter to provide the variables of SQL.
Cursor cur = db.rawQuery("SELECT * FROM TASK WHERE dbDate = ? AND dbTime = ? ", new String[]{AlarmDate, AlarmDate});
Going by your comment 'I have used db = openOrCreateDatabase("Globus", 0, null); where Globus is the db name', you are not using SQLite properly with android.
What you should be doing is creating class which extends SQLiteOpenHelper, then make sure you override the onCreate and onUpgrade methods, these are the methods where you create tables and make changes, it has been said a hundred times on here so I will provide a link to a tutorial: http://www.codeproject.com/Articles/119293/Using-SQLite-Database-with-Android
When you do database operations, on the class call getWritableDatabase (http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase())
I say call getWritableDatabase because that way you don't need to worry if you can write to it, a writable database is also readable. Just FYI. Ask away for more details.
This should be the process of reading (writing is the same, just use what method you want instead of query):
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();//this should lock the tables you are reading
Cursor c = db.rawQuery("select 1 where 1=?", new String[]{"1"});
if(c.moveToFirst()){
do{
//Do what you want with the row
}while(c.moveToNext());
}
c.close();
db.setTransactionSuccessful();
db.endTransaction();
db.close();
Here is the source code of a database helper I wrote, maybe it will help, read through it, understand how it works. https://bitbucket.org/FabianCCook/dbhelper/src/af7a8eba8d1a3f139e4170bbef9f1a2d3fdf1b47/src/nz/smartlemon/DatabaseHelper/ApplicationDataDbHelper.java?at=master
And if you want to know the reason the open methods exist read through this code
(This class was made from the help of someone elses code)
https://bitbucket.org/FabianCCook/dbhelper/src/af7a8eba8d1a3f139e4170bbef9f1a2d3fdf1b47/src/nz/smartlemon/DatabaseHelper/SDCardSQLiteOpenHelper.java?at=master
SQLiteDatabase db = getReadableDatabase();
Cursor cur = db.rawQuery("SELECT * FROM TASK WHERE dbDate = '"+AlarmDate+"' AND dbTime = '"+AlarmTime+"'",new String [] {});
Make sure you have gotten a readable database for 'db' or it will return null everytime.
Also change the end of your raw query to new String [] {}
Hope this helps, this is what I use in my applications.

Removing rows from an Android SQLite Cursor

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.

Categories

Resources