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..
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 have a listview populated from an SQLite database. I have several items that I successfully populate into the listview, however I'm having trouble with one last thing.
I'm trying to queue the sum total of the column KEY_CONTENT6 which is a string type, however it only contains numbers. I'd like to keep it as a string, so to add it up I'm using Double.valueOf(). The problem is this code force closes on queue and I cant figure out whats wrong:
public Cursor queueAll(){
String[] columns =
new String[]{KEY_ID, "sum("+ Double.valueOf(KEY_CONTENT6) +")",
KEY_CONTENT9, KEY_CONTENT10 };
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
null , null, KEY_CONTENT10, null, KEY_CONTENT9+ " DESC");
return cursor;
}
simply use SUM, no need to use anything else..
String[] columns =
new String[]{KEY_ID, "sum(KEY_CONTENT6)",
KEY_CONTENT9, KEY_CONTENT10 };
It is valid for SQLite. Because, no matter what you set data type in SQLite, it stores values as string. So, type conversion is somewhat built-in in SQLite.
You can't use java in a SQL statement, either stick to strait sql or iterate over the cursor and use java to do your calculation.
You can find everything there is to know about sqlite here http://www.sqlite.org/docs.html
SQLite is basically typeless, so you might be able to use SUM on your column even though it is a string. However, if it's meant to be a numeric column, why not give it a number type??
I've successfully copied an existing SQLite database to android, as it was recommended here http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/
and now when i'm writing
Cursor cur = db.db.query("student",
null, null, null, null, null, null);
The app breaks trying to create a cursor. I'm sure there is a "student" table.
Could you help me with suggesting any reasons of why this happens, please?
I just guessing, but db.db.query() looks wrong... you sure you didn't mean db.query() ?
A more collaborative answer than my comment. I would think you'll be fine by doing something like this tutorial does http://droidreign.com/2010/10/dev-tutorials-android-sqlite-database-basics/ . About half the way down is the part you are looking for.
Edit: I guess the problem with your query is that you ask for none of the columns (second parameter in your query). It should probably be at least one of your columns.
It does not seem possible to use REGEXP in a SQLite query in Android. If it is possible, please point me in the right direction.
Is there a way to use a LIKE condition to query for an expression at the beginning of any word in the result?
Example:
Entries:
1. Minimum
2. Aluminum
3. Last Minute
Query:
"min"
Desired Result
(1) Minimum
(3) Last Minute
NOT
(2) Aluminum
This is basically my current code, which would return (2)Aluminum:
public Cursor search(String query) {
return mDb.query(TABLE, COLUMNS, KEY_NAME +" like ?", new String[] { "%"+query+"%" }, null, null, null);
}
Any help will be greatly appreciated!
It's somewhat of a hack, but...
foo LIKE 'bar%' OR foo LIKE '% bar%'
might work for your needs (finding "bar" at the beginning of a word in "foo"). If you also want punctuation to serve as word delimiters, you'd have to add OR clauses for that as well (hence why it's a hack).
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");