Substring for SQLite Android - android

I'm trying to do a particular function for my code. Suppose, in my database, there is an entry called tandoori chicken. How do I code the SQL part so that I can filter the database with chicken tandoori and not just fixed on tandoori chicken?
public class MyDatabase extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "FoodDatabase1.sqlite";
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
And the getFood function.
/*
* Receive searchQuery in string form
* return Cursor object
*/
public Cursor getFood(String searchQuery) {
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String [] sqlSelect = {"_id", "FOOD", "CALORIES"};
String sqlTables = "fooddb1";
String whereClause=null;
String[] whereArgs=null;
/*
*if searchQuery is empty then null will be passed in query() function which
*will display all rows
*if searchQuery is not null it will look for match in the table
*/
if(!searchQuery.equals("")){
whereClause="Food LIKE ?";
/*
*LIKE statement will look for substring in the table if found it will add that row to cursor
*/
whereArgs= new String[] {
"%"+searchQuery+"%"
};
}
qb.setTables(sqlTables);
Cursor c = qb.query(db, sqlSelect, whereClause, whereArgs,
null, null, null);
c.moveToFirst();
return c;
}

You just need to split the substrings by space. For example, you've tandoori chicken as search query string. So, now you need to split the query string by space to make two separate words- tandoori and chicken.
Then the sql query should look like
Select * from foodTable where Food like 'tandoori chicken' or 'chicken tandoori'
To achieve this you might consider doing something like this.
String[] queryWords = searchQuery.split(" "); // Split by space
Now make the words and put them in an ArrayList.
private ArrayList<String> getQueryStrings(String[] queryWords) {
private ArrayList<String> queryStringList = new ArrayList<String>();
// Now let us do some combination of words here and add each combination in the ArrayList.
for(int i = 0; i < possibleCombinationCount; i++)
queryStringList.add(getWordsCombination(i));
return queryStringList;
}
Now make the query string as you like.
String builder = "";
for(String wordsComb : getQueryStrings()) {
// make the query with or
if(builder.length != 0) builder += " or ";
builder += "'%" + wordsComb + "%'";
}
String query = "Select * from foodTable where Food like " + builder;
Now run the rawQuery() on your database.
db.rawQuery(query);
This solution may work well for two or three words in a string while it won't work well for long strings.
If your search is flexible like you just want to find the rows matched with the given strings you might consider using the IN statement.
Select * from foodTable where Food in (queryWords[0], queryWords[1], ....)
Just you need to build the database query of your own with the values separated from the query string by space in queryWords array.
I found this answer relevant to your question too.

Related

Sqlite how to improve performance?

I have to make more than 300 selects from my database.
Each of those queries has to be called inside of a for each loop, here's an example:
for(int id : myids){
Cursor cursor = MyDatabaseHelper.runMyQuery(id);
while(cursor.moveToNext()){
//my stuff...
}
}
MyDatabaseHelper is an instance of a database helper class, the function is like this
public Cursor runMyQuery(int id){
SQLiteDatabase db = this.getWritableDatabase();
Cursor ret = db.rawQuery("select Name, Surname, Age from PTable where Id = " + id, null);
return ret;
}
I've been told that the constant "open and close" of the db because of multiple queries it the cause of my performance issues and I should, instead, make a single query (using union etc).
Changing my code to a single query would mean changing the entire database, and I was hoping not to do that.
Is there anything I can do to improve the performance and keep the multiple selects at the same time?
Thanks
I think what you are looking for is the in clause.
Convert your myids into a string. Something like
String inClause = "(1,2,3)"
and you can use it as
"select Name, Surname, Age from PTable where Id in " + inClause
You can read more of the in operator here
You can return a single Cursor containing all the rows.
First change your runMyQuery() method to this:
public Cursor runAll(String list){
SQLiteDatabase db = this.getWritableDatabase();
String sql = "select Name, Surname, Age from PTable where " + list + " like '%,' || id || ',%'"
Cursor ret = db.rawQuery(sql, null);
return ret;
}
So you pass to the method runAll() a String which is the the comma separated list of all the ids that you have in myids and with th eoperator LIKE you compare it to each id of the table.
You create this list and get the results in a Cursor object like this:
StringBuilder sb = new StringBuilder(",");
for(int id : myids){
sb.append(String.valueOf(id)).append(",");
}
String list = sb.length() > 1 ? sb.toString() : "";
if (list.length() > 0) {
Cursor c = runAll(list);
while(c.moveToNext()){
//your stuff...
}
}

Can't extract integer from cursor after preforming sqlite query in Android

I'm working on an small android app that maintains a small database of tools which I lend out to other people.
As part of the app, I am incorporating an sqllite database, where I am having a bit of trouble performing queries and working with cursors once the queries have been executed.
The code in question is as follows:
String COLUMN_NAME = "toolName";
String[] columns = { COLUMN_NAME };
String selection = COLUMN_NAME + " =?";
String[] selectionArgs = {tool};
Cursor cursor = mToolDb.query(ToolStatisticContract.ToolStatisticEntry.TABLE_NAME, columns,
selection, selectionArgs, null, null, null, null);
return Integer.parseInt(cursor.getString(3));
The contract for the database is as follows:
public class ToolStatisticContract {
public static final class ToolStatisticEntry implements BaseColumns {
public static final String TABLE_NAME = "tooltable";
public static final String COLUMN_TOOL_NAME = "toolName";
public static final String COLUMN_LIFESPAN = "lifespan";
public static final String COLUMN_USAGE = "usageTime";
}
}
I am essentially trying to extract out the value from COLUMN_USAGE, which seems to be producing errors with regards to parsing the value to an integer. The value in the COLUMN is actually an integer typecasted as a String from a previous segment of code, so I'm fairly certain the error is encompasssed with the code snippets above.
Thanks again in advance for all your help!
The code in question is as follows
The net SQL statement is something like:
SELECT toolName FROM tooltable WHERE toolName = ?
And there is no column with index 3, since you are only returning 1 column.
You need to:
Have usageTime in your column list (COLUMNS)
Move the Cursor to a valid row (as it initially is positioned before the first row)
Pass getInteger() the value that lines up with COLUMNS to retrieve usageTime
You could use the following. This uses null instead of columns, which will get all columns (i.e. resolves to SELECT * FROM table). It checks that a row has been returned and only then does it try to get the data. It also closes the cursor (you should close a cursor when done with it). It uses cursor.getInt() to get the integer value rather than convert it from a string to int. It assumes that you'll only get 1 row (if no rows then 0 will be returned).
int returnvalue = 0;
String COLUMN_NAME = "toolName";
String[] columns = { COLUMN_NAME };
String selection = COLUMN_NAME + " =?";
String[] selectionArgs = {tool};
Cursor cursor = mToolDb.query(ToolStatisticContract.ToolStatisticEntry.TABLE_NAME, null,
selection, selectionArgs, null, null, null, null);
if (cursor.getCount() > 0) {
cursor.moveToFirst();
returnvalue = cursor.getInt(2);
//or returnvalue = Integer.parseInt(cursor.getString(2));
}
cursor.close();
return returnvalue;
Note! I haven't checked this just coded it from memory, so apologies for the odd mistake.
To do the above using specific columns then you could use:-
String COLUMN_NAME = "toolName";
String[] columns = { COLUMN_USAGE };
String selection = COLUMN_NAME + " =?";
String[] selectionArgs = {tool};
Cursor cursor = mToolDb.query(ToolStatisticContract.ToolStatisticEntry.TABLE_NAME, columns,
selection, selectionArgs, null, null, null, null);
In which case the column index would be 0 (that is the index is according to the column's in the cursor). However it might be better to use, the following which gets the column index according to the column's name:-
cursor.getInt(cursor.getColumnIndex(COLUMN_USAGE);
The easiest way to read a single value from the database is to use a helper function that allows you to avoid having to handle cursor objects:
String query = "SELECT usageTime FROM tooltable WHERE toolName = ?";
String[] selectionArgs = { tool };
long returnvalue = DatabaseUtils.longForQuery(mToolDb, query, selectionArgs);

Android SqlLite check if two values exist in 2 different columns

I am developing an application where the user inputs title and the date. I want to prevent the duplicated titles being inputted on the same day in to database. I am checking if the title exists on the selected date. However my query seems not to work and i don't know why, the application just crashes.Is this query correct? Can someone help?
public boolean checkExist(String title, String date) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
boolean exists = c.moveToFirst();
c.close();
return exists;
}
One issue that you have is that c.moveToFirst will always fail if a match does not exist as you are trying to move to a row in an empty cursor.
The resolution is to not use c.moveToFirst and instead get the count of the rows and then set the return value accordingly.
e.g.
public boolean checkExist(String title, String date) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
boolean exists = c.getCount() > 0;
c.close();
return exists;
}
The second issue is that the query itself is wrong as you do not have spaces either side of the AND keyword. That is instead of
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
You should have
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +" AND " + DATE+"=?", new String[] {title,date});
Personally, I setup constants for SQL keywords that include the space and then use these. So I'd have something along the lines of +TITLE+"=?" + SQLAND + DATE+"=?". Where SQLAND would be defined along the lines of String SQLAND=" AND ";
PS look at Cricket_007's answer, the code is neater/better it's easier to read.
Your spacing is off. TITLE+"=?" +"AND" + DATE becomes TITLE=?ANDDATE=?
I would suggest this. See DatabaseUtils.queryNumEntries
public boolean checkExist(String title, String date) {
SQLiteDatabase db = getReadableDatabase();
String[] args = new String[] {title,date};
String filter = String.format("%s=? AND %s=?", TITLE, DATE);
return DatabaseUtils.queryNumEntries(db, TABLE_NAME, filter, args) > 0;
}
you should be using c.getCount() instead of c.moveToFirst()
if the value is greater than 0, then it exists

Searching and retrieving specific data from a previously created SQLite Database in Android?

I have an SQLite Database which I made in SQLite Browser and exported to my Android Application through SQLite Asset Helper Library. This database is for reading-only tasks and can't be upgraded or modified.
Now I want to search in an specific column any data the user input in a TextView, and in case the data matches with some value of the column retrieve all the values corresponding from the other columns.
For example:
TABLE FRUITS
_id NAME URL
1 apple R.drawable.apple
2 orange R.drawable.orange
3 kiwi R.drawable.kiwi
Since my application only allows the user to input the NAME field, the query needs to search in the NAME column only, and retrieve the URL value only if exists in the database, otherwise will return nothing.
Here's my code for importing the database:
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import com.readystatesoftware.sqliteasset.SQLiteAssetHelper;
public class MyDatabase extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "fruitManager";
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public Cursor answerRequest(String request) {
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String sqlTables = "FRUITS";
qb.setTables(sqlTables);
String[] sqlSelect = {"0 _id", "NAME", "0 URL"};
Cursor c = qb.query(db, sqlSelect, null, null,
null, null, null);
return c;
}
}
And from here I made the request:
public class Request {
private Cursor cursor;
private MyDatabase db;
String request;
String url;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sqlite_asset_helper);
public void onClick(View v) {
request = mEdit.getText().toString().toLowerCase();
db = new MyDatabase(this);
cursor = db.answerRequest(request);
url = cursor.getString(c.getColumnIndex("NAME"));
System.out.println("Your request was: " + request +
" and has this URL: " + url);
}
}
protected void onDestroy() {
super.onDestroy();
cursor.close();
db.close();
}
Still, loads of code are needed for do the query but I don't know exactly how to implement them in this case (due to imported database). Thanks in advance.
UPDATE: I'm kinda desperate so if you don't have the answer but know an alternative for do the task (like using another database handler instead of SQLite) I will accept your suggestions as the correct answer.
Only restriction is: Has to be an offline solution (no internet connection needed for access the database).
Your current query looks like this:
`select 0 _id, NAME, 0 URL from FRUITS`
Notice you aren't using the request string anywhere. You are also selecting integer literal 0 and aliasing this to other column names--there doesn't seem to be any reason for this. As is, your results would be
_id NAME URL
0 apple 0
0 orange 0
0 kiwi 0
What you want is the following:
`select * from FRUITS where NAME = request`
Here's how I would write it:
public Cursor answerRequest(String request) {
SQLiteDatabase db = getReadableDatabase();
String table = "FRUITS";
String where = "NAME = ?";
String[] whereArgs = {request};
// select * from fruits where name = request
return db.query(table, null, where, whereArgs, null, null, null);
}
And elsewhere when you want to retrieve the values:
db = new MyDatabase(this);
Cursor cursor = db.answerRequest(request);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
// cursor is not empty, read values here
String url = cursor.getString(cursor.getColumnIndex("URL"));
}
} finally {
cursor.close();
}
}

The sql query does not pass the arguments

I'm writing an android application and I need to search the data base, this is the method I use:
public Cursor getData(String table, String keyword, SQLiteDatabase db){
String selection;
Cursor cursor;
switch (table){
case "User":
String [] projection = {id,name,phone};
selection = "username LIKE ?";
String [] selection_arg = {keyword};
cursor = db.query("User",projection,selection,selection_arg,null,null,null);
break;
//omitted
default:
return null;
}
return cursor;
The user put in the keyword
keyword = search_user.getText().toString();
Cursor cursor = dbHelper.getData(ShippingApplication.User.USER_TABLE,keyword,db);
The code does not work, when I debug, I see the mQuery of the db variable is:
SQLiteQuery: SELECT userID, userName, phoneNumber FROM User WHERE userName LIKE ?
It looks like the query does not pass the value of the keyword in to the sql command.
Could someone tell me what's wrong?
EDIT 2: I change the code a little bit and now it works:
String selection = ShippingApplication.User.name + " LIKE '%" + keyword + "%'";
Cursor cursor = db.query(The table name,projection,selection,null,null,null,null);
try this way
please check your SQLiteDatabase object is not null
after that check Table is created or not
i get the cursor count i already debug it and it's working fine for me
public Cursor getData(String table, String keyword, SQLiteDatabase db){
String selection;
Cursor cursor;
switch (table){
case "Tbl_staticContent":
String [] projection = {"PageTitle","Content"};
selection = "PageTitle LIKE ?";
String [] selection_arg = {keyword};
cursor = db.query("Tbl_staticContent",projection,selection,selection_arg,null,null,null);
Log.e("count",""+cursor.getCount());
//I have create table and stored data and also check the like condtion also it's work fine and get the cursor.getCount() > 0 also .
break;
default:
return null;
}
return cursor;
}

Categories

Resources