In my search module I am using SQLite database. Sometimes I'm searching more than two values. So I am using AND condition and sometimes searching only one value. These two cases I need to implement in a single query. Please help me.
This is the query:
Cursor dbcur = myDB.rawQuery("select * from "+dbtable+" where Status='"+item+"'AND ball_court='"+ball+"'AND Tovendor='"+vendor+"'", null);
Sometimes I am searching status and ball_court, tovendor and sometimes I am searching status only. How to solve this problem?
Build the query string in stages, rather than all at once. If you're always going to select against the status, put that in the basic WHERE clause, then add any additional expressions. Use parameters (which you can do with SQLiteDatabase.query) rather than concatenating values into the query itself to prevent SQL injection. dbtable better not come from untrusted sources (e.g. users, the database itself). My Java's a little rusty, but try something like the following to start:
List<String> argList = new LinkedList<String>();
String selection = "Status=?";
argList.add(item);
if (ball != null && ball.length()) {
selection += " AND ball_court=?";
argList.add(ball);
}
if (vendor != null && vendor.length()) {
selection += " AND Tovendor=?";
argList.add(vendor);
}
String[] argArray = new String[argList.length()];
argList.toArray(argArray);
// columns is a String[] of column names
Cursor dbcur = myDB.query(false, dbtable, columns, selection, argArray, null, null, null);
Rather than appending strings, you might want to use a StringBuilder.
As for SELECT *, read "What is the reason not to use SELECT *?"
You might be able to get some answers if you post a sample query as well as what you might search for! I didn't totally understand your question, as I would/should be able to help out.
Related
I am building an Android app that uses a SQLite database.
For this one task I have to run a query that looks like this:
SELECT item.id, item.price, t1.quantity
FROM item, (SELECT id, price
FROM list
WHERE list.state = 'sold') t1
WHERE item.id = t1.id
So far, I have tried:
Cursor c = resolver.query(uriRawQuery, null, selection, null, null)
where uriRawQuery is used to tell the ContentProvider that it should perform a db.rawQuery(selection, null) and selection is a string similar to the query above.
The problem is no data is returned into the Cursor. When I call c.moveToFirst() I get false.
The weird thing is that if I open the database file in SQLite Manager and run the exact same query I get results.
I know I can modify the query to make a join between the original list and item tables but I find it to be less efficient that way.
Any ideas would be very appreciated as I have spent too man hours on this already.
EDIT
I know what a join is, what I said is that it is a lot more efficient if I do it like this instead of using the entire list table.
I forgot a very important aspect
The WHERE clause looks like
" WHERE list.state = 'sold' and list.name like '" + arg + "%'"
where arg is a string.
I managed to solve the problem, I still don't know why this was happening but at least I got the Cursor to actually select the rows.
After many trials I thought about ditching the syntax above and write this instead:
" WHERE list.state = 'sold' and list.name like ? "
and move the argument in
selectionArgs = new String[]{arg + "%"}
I am going to wait a while before accepting the answer, in case someone provides an explanation as to why even though both queries look exactly the same they get different results.
I'm passing the below statement as a rawQuery in Android:
SELECT DISTINCT ltUsers._id,ltUsers.NAME,ltUsers.GLOBAL_ID, ltGroups.GROUP_NAME
FROM ltUsers
JOIN ltGroups ON (ltUsers.GROUP_ID = ltGroups.GLOBAL_ID)
WHERE ltgroups.GLOBAL_ID = ? " +
ORDER BY ltUsers.NAME ASC,ltgroups.GLOBAL_ID ASC;
With the rawQuery as follows:
Cursor c = db.rawQuery(sql,args)
It works just fine if I pass a value to the parameter, e.g.
String[] args = new String[]{"2"}
However, I also want to be able to show all rows, unlimited by the GLOBAL_ID in the WHERE clause. Testing on a dump of my SQLite database outside of Android - as well as in Android by just writing the parameter directly into the statement - shows the following clause to be a valid way to do this:
WHERE ltGroups.GLOBAL_ID = ltGroups.GLOBAL_ID
Yet when I pass the field reference ltGroups.GLOBAL_ID or [ltGroups].[GLOBAL_ID] as a parameter it fails to return any rows in the rawQuery. Any ideas on why this might be happening? Happy to produce any extra information.
Parameters always replace specific values, not anything else.
When you put the string "ltGroups.GLOBAL_ID" into the parameters array, it is interpreted as exactly that, a string.
(To show all records, just omit the WHERE clause.)
I am trying to create a dictionary application on Android. I have a database of 80000 articles. When user enters a word in an EditText, I want to show suggestions in a ListView, To do that I use the following code:
public Cursor query(String entry){
String[] columns = new String[]{"_id", "word"};
String[] selectionArgs = new String[]{entry + "%"};
return mDB.query("word", columns, "word LIKE ?", selectionArgs, null, null, null);
}
and I use SimpleCursorAdapter for the ListView.
The problem is that suggestions appear very late. I think the reason is LIKE in the SQL. I do not know any other way to do that. Is there anything I can do to boost the performance of getting the suggestions?
You might find that adding an index on the word column helps a lot. See the documentation.
So you might try this, just after you create the table:
CREATE INDEX word_idx ON word (word);
(Note: I'm not sure if having the table and column both named word will cause syntax issues here. Try it and see!)
Aside from the obvious index you should look into using full text search with MATCH rather than like if this is a dictionary. Android should support FTS3.
Check out http://www.sqlite.org/fts3.html and some answers here on SO regarding fts3 on Android.
It seems that the words should start with the string.
Maybe this type of trick could help: SQLite FTS3 simulate LIKE somestring%
As a simple alternative, you can limit the suggestions in the arbitrary order with Limit as in this post: Using the LIMIT statement in a SQLite query
mDB.query("word", columns, "word LIKE ?", selectionArgs, null, null, null, "LIMIT 150" );
Since all the results are equally valid suggestions, the order will not matter.
Also you wonT be able to show crazy amount of suggestions anyway so you can simply use some fixed limit count depending on your UI. I gave 150 as an example.
Hope it helps..
I am trying to get call log by using the CallLog.Calls content provider. However, I am little lost about the query I need to make. I am able to make a query and load the result in a ListView. But the query return all types of call.
Of course I can use a switch-case and take appropriate action as per the types of call returned. But for my program I only need the outgoing call logs.
So, how do I modify the query to get only outgoing call types. (I believe I have to use CallLog.Calls.OUTGOING_TYPE somewhere?). I have tried to modify the query in various ways but I keep getting error. If I try to supply the CallLog.Calls.OUTGOING_TYPE as an selection arg I get an error as its an int type and the query looks for String type.
I may be missing something simple, but can't figure it out. Any help would be much appreciated. Thank You. Here's my query below,
getContentResolver().query(CallLog.Calls.CONTENT_URI,null, null, null, ORDER_BY );
Try this code snippet:
Cursor c = getContentResolver().query(CallLog.Calls.CONTENT_URI, null,
CallLog.Calls.TYPE + "=?",
new String[] { String.valueOf(CallLog.Calls.OUTGOING_TYPE) },
ORDER_BY);
Android's API provides a clean mechanism via SQLite to make queries into the contact list. However, I am not sure how to limit the results:
Cursor cur = ((Activity)mCtx).managedQuery(
People.CONTENT_URI,
columns,
"LIMIT ? OFFSET ?",
new String[] { Integer.toString(limit), Integer.toString(offset) },
null
);
Doesn't work.
Actually, depending on the provider you can append a limit to the URI as follows:
uri.buildUpon().appendQueryParameter("limit", "40").build()
I know the MediaProvider handles this and from looking at recent code it seems you can do it with contacts too.
You are accessing a ContentProvider, not SQLite, when you query the Contacts ContentProvider. The ContentProvider interface does not support a LIMIT clause directly.
If you are directly accessing a SQLite database of your own, use the rawQuery() method on SQLiteDatabase and add a LIMIT clause.
I found out from this bug that Android uses the following regex to parse the LIMIT clause of a query:
From <framework/base/core/java/android/database/sqlite/SQLiteQueryBuilder.java>
LIMIT clause is checked with following sLimitPattern.
private static final Pattern sLimitPattern = Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
Note that the regex does accept the format offsetNumber,limitNumber even though it doesn't accept the OFFSET statement directly.
I think you have to do this sort of manually. The Cursor object that is returned from the managedQuery call doesn't execute a full query right off. You have to use the Cursor.move*() methods to jump around the result set.
If you want to limit it, then create your own limit while looping through the results. If you need paging, then you can use the Cursor.moveToPosition(startIndex) and start reading from there.
You can specify the "limit" parameter in the "order" parameter, maybe even inside other parameters if you don't want to sort, because you'll have to specify a column to sort by then:
mContentResolver.query(uri, columnNames, null, null, "id LIMIT 1");