Programmatically search for best match in sqlite database? - android

I am currently implementing a search feature in an appliction to take a user input and query the database for similar results. I have created the following database query:
String proQuery = "SELECT * FROM " + DATABASE_TABLE + " WHERE "
+ KEY_NAME + " LIKE '%" + keyword +"%'";
Obviously this query has a number of limitations due to a very generic sql statement. For example, if I start typing something in the middle of the word, it will show up first in the list if it has a lower row number in the database.
Are there libraries that help make a more intelligent search feature than this very generic sql statement? I am not sure what keywords could describe this functionality what I'm looking for, is there some field of "search algorithms" for android?

Maybe UNION is what you're looking for:
SELECT * FROM (
SELECT * FROM table_name WHERE keyname LIKE 'keyword%' ORDER BY keyname
) alias_t1
UNION ALL
SELECT * FROM (
SELECT * FROM table_name WHERE keyname LIKE '%keyword%' AND keyname NOT LIKE 'keyword%' ORDER BY keyname
) alias_t2;

Related

SQlite primary key doesn't work as expeted

I have the following table:
String sqlStatement = "CREATE TABLE " + CallsEntry.TABLE_NAME + "(";
sqlStatement += CallsEntry.FIELD_CALL_ID + " INT PRIMARY KEY DESC,";
sqlStatement += CallsEntry.FIELD_CALLER_PHONE + " TEXT,";
sqlStatement += CallsEntry.FIELD_INSERTION_DATE_MILLIS + " INT); COMMIT;";
db.execSQL(sqlStatement);
Please note that the primary key is descending.
Then I expect from my experience with SQL server that the following query will yield the records in an descending order:
SELECT * FROM tblCalls;
However, this is not the case. I'm getting the records in ascending order. I have to use this:
SELECT * FROM tblCalls ORDER BY CallId DESC;
Why is that? Can I do something differently and get the records in descending order?
There is no such thing as default key order in SQLite.
Depends on documentation:
If a SELECT statement that returns more than one row does not have an
ORDER BY clause, the order in which the rows are returned is
undefined. Or, if a SELECT statement does have an ORDER BY clause,
then the list of expressions attached to the ORDER BY determine the
order in which rows are returned to the user.
So default order is underfined without ORDER BY clause.
Does this produce the right order?
SELECT CallId FROM tblCalls

How can i order my data Ascending by Time

Like said in the title I am trying to sort my data from sqlite database to ascending time. Here is what I have so far:
Cursor display = db.rawQuery("SELECT * FROM "+TableName + " ORDER BY Time ASC",null );
It displays data however it doesnt sort according to my Time with formade ##.## 24hr time. Hope someone can help.
Try "SELECT * FROM " + tableName + " ORDER BY time(Time)". PS: ASC is default ;)
You can use the strftime() function:
SELECT *
FROM my_table
ORDER BY strftime('%H:%M:%S',my_column)
Here I created a fiddle as example.
The raw query should be something like:
"SELECT * FROM " + TableName + " ORDER BY strftime('%H:%M:%S'," + my_column + ")"
NOTE: strftime() function is the more general function that you can use for manipulate date. But, for this specific case you can also use time(). Indeed, as the document that I linked says:
time(...) is equivalent to strftime('%H:%M:%S', ...)

Displaying rows from different tables to one ListView in Android - without SQL JOIN

I'm super-novice at Android programming and have this project I'm stuck on.
I have a database of (conlang) dictionaries where each language is in its own table. The user searches these and the results will display in a ListView. Right now, I've got it working to search only one table.
I want it to be able to search all three tables and display the results in one ListView with rows from each of the tables. I'd like to indicate which table each row came from. The results would display something like:
From language
Lang Term : English term
Additional information
I've set up a CursorAdapter and have this currently working for one of the three tables.
...
Since the dictionaries came from different sources, they have different information. As an example:
One has the columns EngTerm, VLangTerm, FullDefinition
Another has EngTerm, RLangTerm, PartOfSpeech
And the other has EngTerm, GLangTerm, PartOfSpeech, and PronounciationGuide (possibly).
For example, table1 might contain results for "land," "landing gear" and "landscape" and table2 might contain "land," "landing" and "island" and table3 might contain "bland" and "homeland."
The user can search these tables right now only by the english term, and can select to match by full word or partial word.
Because of how they are structured, I'm guessing there is no way to do a JOIN query.
I don't know if this helps at all, but right now, I've got this method in my SQLiteOpenHelper class:
public Cursor searchDictionaryByEnglish
(boolean matchFullWordOnly, String searchTerm) {
String sql = "SELECT * FROM " + TABLE_VULCAN +
" WHERE " + COLUMN_ALL_ENG_TERM + " MATCH ?";
if (!matchFullWordOnly)
searchTerm = "*" + searchTerm + "*";
return mDataBase.rawQuery(sql, new String[]{searchTerm});
}
(It is an FTS3 table it's searching, thus the MATCH rather than LIKE.)
I hope I've made it clear what I'm trying to accomplish, but I'm not sure where to start. I've found some answers about MergeCursor but I don't know how to apply that because of the different number and names of columns.
Here's how to do a union if you don't have one of the columns in one of the tables, it will work if you're only searching through the common column, that all the tables have.
SELECT field1 ,
field2 ,
field3
FROM ( SELECT field1 ,
field2 ,
field3
FROM table1
UNION
SELECT field1 ,
field2 ,
field3
FROM table2
UNION
SELECT field1 ,
field2 ,
NULL AS field3
FROM table3
) tbl
WHERE tbl.field1 LIKE '%search_string%'
Note the NULL AS field3 in the last UNION.
Create a Adapter that does accept the fields you require to display.

SQLlite like statement replace space with special char

I have an SQLlite database with a list of cities.
My autoCompleteTextView is linked to this database but I have one problem.
There are a lot of cities in my database like this:
Sint-Truiden
Sint-Pieters-Rode
Sint-Rijkers etc...
But a lot of users will just type Sint Truiden and receive no result.
This is what I have so far:
String sql = "";
sql += "SELECT * FROM " + TABLE_CITIES;
sql += " WHERE " + KEY_NAME + " LIKE '%" + searchTerm + "%'";
How can I adjust my SQL to achieve my goal?
One solution is to normalize the search term and the database content. For example, you could add to the table a column containing the normalized name. Some normalisation examples :
Replace any kind of separator (dash, point, multiple spaces) with one space
Convert to lowercase
Remove accents

Speeding up DB queries on Android

I'm using SQLite on Android using SQLiteDatabase (http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html)
I am developing a bible application, which has a single table with the following columns:
book : int
chapter : int
verse : int
wordIdx : int
strongId : string
word : string
each sentence is broken down in to a series of strongId/word pairs, so wordIdx is used to order the words, strongId is simply a index in to a concordance, and word is the word in the sentence.
so I have 300,000 rows
the bottleneck appears to be my query to get a list of words for each verse:
My SQL is effectively this:
SELECT strongId, word FROM ? WHERE book=? AND chapter=? AND verse=?
Here is the code:
Cursor cursor = mBible.database().rawQuery("SELECT " + KEY_STRONGID + "," + KEY_WORD + " FROM " + tableName() + " WHERE " + KEY_BOOK + "=? AND " + KEY_CHAPTER + "=? AND " + KEY_VERSE + "=?" , new String[] { String.valueOf(mChapter.mBook.index()), String.valueOf(mChapter.index()), String.valueOf(verse) });
cursor.moveToFirst();
mWordList = new ArrayList<Word>();
do {
mWordList.add(new Word(cursor.getString(1), cursor.getString(0)));
} while (cursor.moveToNext());
Now, I've tried putting each chapter in to its own temporary view (using CREATE TEMP VIEW) which cuts down the records to about 400 in my example how ever it is still taking far to long to query
Its taking of the order of 30 seconds to generate the text for two chapters to display to the user (using a temporary view and without using a temporary view). It takes about 5 seconds if I set up a dummy list of words to avoid the database query.
How can I improve the performance of this? It seems as if a temp view is having no impact on performance as I had hoped.
A view does not change the performance of a query; it just saves the query itself, not the results of the query.
If you open your database with the sqlite3 command-line tool on your desktop machine, you can use the EXPLAIN QUERY PLAN command to check how efficient your queries are.
Without any indexes, you query always scans the entire table:
> sqlite3 bible.db
SQLite version 3.7.15.2 2013-01-09 11:53:05
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> EXPLAIN QUERY PLAN SELECT strongId, word FROM MyTable WHERE book=1 AND chapter=2 AND verse=3;
0|0|0|SCAN TABLE MyTable (~1000 rows)
With an index on your three lookup fields, SQLite can do a fast search in the index and needs to read only the matching records from the table:
sqlite> CREATE INDEX b_c_v ON MyTable(book, chapter, verse);
sqlite> EXPLAIN QUERY PLAN SELECT strongId, word FROM MyTable WHERE book=1 AND chapter=2 AND verse=3;
0|0|0|SEARCH TABLE MyTable USING INDEX b_c_v (book=? AND chapter=? AND verse=?) (~8 rows)
If you create a covering index (with all fields used in the query, lookup fields first), SQLite does not need to read from the table at all. However, this does not give a big speedup over a normal index, and might not be worth the additional storage cost:
sqlite> CREATE INDEX cov ON MyTable(book, chapter, verse, strongId, word);
sqlite> EXPLAIN QUERY PLAN SELECT strongId, word FROM MyTable WHERE book=1 AND chapter=2 AND verse=3;
0|0|0|SEARCH TABLE MyTable USING COVERING INDEX cov (book=? AND chapter=? AND verse=?) (~8 rows)
Please note that SQLite can use at most one index per table in a query, so it does not always make sense to create multiple indexes.
Use EXPLAIN QUERY PLAN to check which indexes are actually used, and whether you can create a few indexes to optimize most of your queries.
Also see the Query Planning documentation.
I ended up creating temporary tables and performance is now acceptable

Categories

Resources