SQLite LIKE alternative for REGEXP, Match Start of Any Word - android

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).

Related

SQLite - Queries with non-English characters don't show any results

I'm using a SearchView widget and it works well, except for the fact the if the string I enter contains any non-English character the result is empty, even if it is clear that there ARE results
Example:
In the image shown above there are two results for the string "chu" but if I type "ñ" the ListView won't show any results and it's obvious that there are results.
This is what I've tried so far
public Cursor searchProductByDescription(String description) {
String where = PRODUCT_DESCRIPTION + " LIKE LOWER( ? ) ";
String[] whereArgs = { "%" + description + "%" };
this.openReadableDB();
Cursor cursor = db.query(PRODUCT_TABLE, null, where, whereArgs, null,
null, null);
if (cursor != null) {
cursor.moveToFirst();
}
this.closeDB();
return cursor;
}
I'm not sure if this is an issue related to the searchview widget or to SQLite.
I've seen a couple of question in which they suggest converting the string to LOWER o UPPER case, but this solution didn't work for me.
I'd really appreciate if you could help me here.
Thanks
LOWER() only knows how to lowercase ASCII characters. LIKE is also case insensitive only with ASCII characters. And ñ is not an ASCII character.
For a solution, consider the following:
Add another column to your table that you use for searches and use the original column only for display purposes.
Store data in this column in a normalized form such as NFC and with the case converted consistently to upper/lowercase. For example:
String stringToStore = Normalizer.normalize(originalString.toLowerCase(), Normalizer.Form.NFC);
Normalize your search strings similarly in code.
If you want to ignore accent e.g. have n also match ñ, use a slightly different approach to remove the accents.

Single quote (') in edittext makes my program crash

If I write something into an edittext that contains single quote (') my program crashes. With this edittext I can search for things in my database and some of them contain this single qoute (or apostrophe whatever name it has but the point is that it's about the single qoute). I assume it has some special functions and this is why it crashes. Is there any option to ignore its function or solve this problem somehow?
for example, an item in my database:
cv.put(KEY_NAME, "Jonh's idea");
cv.put(KEY_HOTNESS, "amazing");
cv.put(KEY_MONEY, "500");
ourDatabase.insert(DATABASE_TABLE, null, cv);
Then when I search for it with this method:
return ourDatabase.query(DATABASE_TABLE, new String[] {"_id", "idea_name",},
"idea_name like " + "'%" + qq + "%'", null, null, null, null);
where qq is given by the user (for example Jonh's idea), it crahses. And yes, I get syntax error.
Sounds like the ' is causing an SQL injection of some sort... the ' is causing a syntax error in your SQL statement. There are several things you might consider double checking:
rawQuery() will not protect you from SQL injections, so avoid using it (rather, use the query, insert, update, and delete methods instead).
Prefer formatting your selection and selectionArgs as follows (as it will protect you from SQL injections):
selection = "col_1 = ?";
selectionArgs = new String[] { "value_1" };
(note that the values in the String[] replace the ?s in the selection string).
Set an inputType on your EditText to prevent users from entering these characters in the first place (i.e. if you only want users to enter numbers, then set android:inputType="number").
Overall, as long as you correctly make use of the Android methods in the SQLiteDatabase class, you shouldn't run into any problems with SQL injections (Android does a good job at cleaning this up for you). That said, if you don't choose to make use of these special-purpose methods, then you should check the content of the String at runtime and protect against characters such as ', ;, ", etc. by escaping them.
You can refer to this post for more information:
Android Single Quote In SQL With a LIKE StateMent
You need to use the selectionArgs argument to escape the string (so that the single quote in it doesn't break the SQL). Try something like this:
return ourDatabase.query(DATABASE_TABLE, new String[] {"_id", "idea_name",}, "idea_name like ?", new String[] { "%" + qq + "%" }, null, null, null);
It seems like SQL-injection. U have to escape your input.
One more jugaad. You can replace ' with `. You won't have to recheck your code. Just modify the following:
String input = edittext.getText().toString();
if(input.contains("'"))
{
input = input.replace("'", "`");
}
//now proceed with the database operation ...
This will enable the user to input text like RD's jugaad to RD`s jugaad

Android SQLite very slow lookup

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..

How can I return a record based on only a partial match of that record?

I've done quite a bit of research on what I thought would be an easy question but I cannot find what I am looking for. I am simply trying to return a record as a match with only a search term matching part of the text in the record.
For example, if the user searches for "ed" I would like any record that contains "ed" to be returned. So if there was a record with the name "Edward" in the name column it would be returned as a match. If there was a record with "finished" in the description, it would also return that record as a match.
I have looked into full text search but not sure if this is something that I would need to do or if it would even do what I need.
As always, I'm not looking for an answer per say, I'm just looking for a direction.
Never used SQLite before, but does it have the "LIKE" operator?
In MySQL, you can do something like:
SELECT name FROM list WHERE name LIKE '%ed%';
Here is some code that will do what you want if you are querying a content provider. If you are querying a sqlite database object directly, the parameters are similar but different.
String search = "ed";
// surround it with the SQL wildcard '%'
String q = "%" + search + "%"
Cursor c = getContentResolver().query(uri,
new String[] { column1, column2 },
"column_name like ?",
new String[] { q },
null);
The snippet will search the content provider at uri for the string ed in column_name.

How to solve all in one query?

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.

Categories

Resources