Querying sqlite in android - android

I'm creating a database for my game, everything is working until I want to query one item.
I have been trying few different methods and I can't make it work. I just simply don't see the error in my code.
The code is as follows:
public Item getItem(String icon) {
String[] columns = {KEY_ID, KEY_TYPE, KEY_ICON, KEY_LEVEL, KEY_ARMOR, KEY_DAMAGE, KEY_BUY, KEY_SELL};
Cursor cursor = db.query(DB_TABLE, columns, KEY_ICON + "=" + icon,
null, null, null, null);
Item item=null;
if(cursor != null && cursor.moveToFirst()) {
item= new Item(cursor.getString(TYPE_COLUMN),
cursor.getString(ICON_COLUMN),
cursor.getString(LEVEL_COLUMN),
cursor.getString(ARMOR_COLUMN),
cursor.getString(DAMAGE_COLUMN),
cursor.getString(BUY_COLUMN),
cursor.getString(SELL_COLUMN)
);
}
return item;
}
The error I'm getting is
No such column: fast_boots (code 1): while compiling: SELECT id, type,
icon, level, armor, damage, buy, sell from items where icon=fast_boots
When trying to find .getItem("fast_boots"); I do see the fast_boots in my sql database

To make the query work, maybe you should try this :
KEY_ICON + "= '" + icon + "' "
As 'icon' is a string value. Since you're not specifying it, it is probably trying to understand it as being a column in the projection
This is the wrong way of implementing such functionality, though. Do not perform database queries on the getItem() method itself (main thread), it deserves to run in background, so it won't affect the main thread.
Please read about AsyncTask.

Try this
Cursor cursor = db.query(DB_TABLE, columns, KEY_ICON + "='" + icon +"'",
null, null, null, null);
I added '

Related

Get a SQLite row based on title and date

I want to get a single row based on title and date.
I have created some code, but i it correct? What are all the null-fields in the code?
public Cursor getRecordFromMondayByTitleDate(String inpRowTitle, String inpRowDate) throws SQLException
{
Cursor mCursor =
db.query(DATABASE_TABLE_MONDAY, new String[] {KEY_M_ROWID, KEY_M_TITLE, KEY_M_DATE,
KEY_M_WEIGHT, KEY_M_SET_A, KEY_M_SET_B,
KEY_M_SET_C, KEY_M_SET_D},
KEY_M_TITLE + "= '" + inpRowTitle + "'",
null,
KEY_M_DATE + "= '" + inpRowDate + "'",
null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
My database table DATABASE_TABLE_MONDAY layout is the following:
private static final String DATABASE_CREATE_TABLE_MONDAY =
"create table if not exists " + DATABASE_TABLE_MONDAY + " (m_id integer primary key autoincrement, "
+ "m_title VARCHAR not null, m_date date, m_weight DOUBLE, m_set_a INT, m_set_b INT, m_set_c INT, m_set_d INT);";
Thanks for the help!
I believe your query should look more like this:
db.query(DATABASE_TABLE_MONDAY,
new String[] {KEY_M_ROWID, KEY_M_TITLE, KEY_M_DATE, KEY_M_WEIGHT, KEY_M_SET_A, KEY_M_SET_B, KEY_M_SET_C, KEY_M_SET_D},
KEY_M_TITLE + "='" + inpRowTitle + "' AND " + KEY_M_DATE + "='" + inpRowDate + "'",
null,
null,
null,
null);
Your table and columns parameters were correct. The third parameter, the selection parameter, is essentially the WHERE clause from SQL, so you want both your title and date specified here. The fourth parameter is selectionArgs, and is there to "help" with coding the selection. If you specify a selection with question marks, the question marks are replaced, in order, with the values in the array you provide. Using selectionArgs is not necessary, and you can pass null if your selection is written in full. After that, the parameters specify how you want the query returned to you, and all may be passed a null value. The fifth is groupBy, and corresponds to the SQL clause GROUP BY. The sixth corresponds to HAVING, the seventh to ORDER BY. The last parameter is limit, and just puts a cap on how many records a query returns. If you don't need to limit your query, you can just omit this parameter, as there is a query() method without limit. If you're unfamiliar with SQL, you may want to do a little studying to know what each of those clauses does for your query.

Update row in SQlite database by row position in android

I have database which contains "date" column and "item" column.
I want that user could update specific row in the database.
I trying to do it with update method in SQLiteDatabase class.
My problem is that i dont know how to make update method find exactly the row i want.
I saw some example that use it with parameters from one word.
like this:
ourDatabase.update(tableName, cvUpdate, rowId + "=" + item , null);
My problem is that i want to update the row that have specific item and date. so the name of the item alone is not enough.
I tried this code below but its didnt work, hope youll can help me.
public void updateEntry(String item, String date) throws SQLException{
String[] columns = new String[]{myItem, myDate};
Cursor c = ourDatabase.query(tableName, columns, null, null, null, null, null);
long position;
ContentValues cvUpdate = new ContentValues();
cvUpdate.put(date, myDate);
cvUpdate.put(item, myExercise);
int itemAll = c.getColumnIndex(myItem);
int dateAll = c.getColumnIndex(myDate);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
if (c.getString(itemAll).equals(myItem) && c.getString(dateAll).equals(myDate))
{
position = c.getPosition();
break;
}
}
ourDatabase.update(tableName, cvUpdate, rowId + "=" + position , null);
}
First, the columns String[] is supposed to contain column names, such as "_ID", or whatever are the column names you have used. Given that you compare the content of the column myItem with the object myItem, I assume there is a confusion somewhere here.
Secondly, rowId and position are different things in SQL, especially if you delete rows, as the row id usually is autoincrement, and especially since your query is not explicitely sorted. Replacing c.getPosition() by c.getLong(c.getColumnIndex(ID_COLUMN)) would make more sense.
Thirdly, sql is nice because you can query it. For example, rather than get all items and loop to find the matching date and item, you can :
String whereClause = ITEM_COLUMN + " = ? and " + DATE_COLUMN + " = ?";
String[] whereArgs = new String[] { item, date };
Cursor c = ourDatabase.query(tableName, columns, whereClause, whereArgs, null, null, null);
instead of your for loop.
Forthly, you can even make the query in the update :
String whereClause = ITEM_COLUMN + " = ? and " + DATE_COLUMN + " = ?";
String[] whereArgs = new String[] { item, date };
ourDatabase.update(tableName, cvUpdate, whereClause, whereArgs);
Extra tip: use full caps variable names for contants such as column names, it help with readability.

How to check if data already saved in Android database

I am trying to check if the text the user inputs is already in my database but unsure how this should be done.
So I can fetch the data from my database by calling the following in my database helper class:
public Cursor fetchDamagedComponentsForLocation(long damagedComponentId) {
Cursor mCursor =
rmDb.query(true, DAMAGED_COMPONENTS_TABLE, new String[] {
COMPONENT_ID, LOCATION_LINK, RUN_LINK, AREA_LINK, INSPECTION_LINK, LOCATION_REF, RACKING_SYSTEM, COMPONENT, POSITION, RISK, ACTION_REQUIRED, NOTES_GENERAL, MANUFACTURER, TEXT1, TEXT2, TEXT3, TEXT4, NOTES_SPEC},
LOCATION_LINK + "=" + damagedComponentId, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
For each of the database entries I need to check if two user inputs match two of the database fields (in this case COMPONENT and POSITION) which I get from my Spinners when the user clicks on the save button:
String component = ((Cursor)componentSpinner.getSelectedItem()).getString(2).toString();
String position = ((Cursor)positionSpinner.getSelectedItem()).getString(1).toString();
This is basically to make sure there is not already that component saved.
I'm sure this is quite simple, but I can't work out how to do it..
edit - following Sams advice, I have added the following class to my databased helper class:
public boolean checkIfComponentAlreadySaved(long locationId, String component, String position) {
Cursor mCursor = rmDb.query(DAMAGED_COMPONENTS_TABLE, new String[] {"1"},
LOCATION_LINK + " = " + locationId + " AND " + COMPONENT + " = " + component + " AND " + POSITION + " = " + position, null, null, null, null, null);
boolean result = mCursor.moveToFirst();
mCursor.close();
return result;
}
However, I am getting the following error:
android.database.sqlite.SQLiteException: near "pin": syntax error: , while compiling: SELECT 1 FROM damaged_components_table WHERE location_link = 3 AND component = Locking pin AND position = Not Applicable
I'm guessing this is because I am comparing Strings, but any suggestions?
moveToFirst() returns true if one or more rows exist, false if the Cursor is empty. So create a new method like this:
public boolean isComponentDamagedForLocation(long damagedComponentId) {
Cursor mCursor =
rmDb.query(DAMAGED_COMPONENTS_TABLE, new String[] {"1"},
LOCATION_LINK + "=" + damagedComponentId, null,
null, null, null, null);
result = mCursor.moveToFirst();
mCursor.close();
return result;
}
The exact columns don't matter so you can pass anything that you want, the WHERE clause is the heart of this query. Use this Java method, to test if the data exists. If isComponentDamagedForLocation) is false, then insert the data.
Addition
Since you are using Strings in your query you should use the replacement character (?) to prevent the error you are seeing now and protect yourself from SQL injection attacks:
public boolean checkIfComponentAlreadySaved(long locationId, String component, String position) {
Cursor mCursor = rmDb.query(DAMAGED_COMPONENTS_TABLE, new String[] {"1"},
LOCATION_LINK + " = " + locationId + " AND " + COMPONENT + " = ? AND " + POSITION + " = ?",
new String[] {component, position}, null, null, null, null);
// etc
I'm confused. You're retrieving data from the database in a Cursor, but you're also getting Cursor IDs from the Spinner? What's the source of the spinner data? getSelectedItem is a method of AdapterView, which assumes that each entry in the View is bound to a row in the backing data. getSelectedItem returns an "id" value in the backing data of the currently selected bound View.
Step back and think about the problem logically. What data is in the database? What data is the user entering? How do you make a record of what the user selected, and look for that selection in data you have in the database? Don't try to do fancy shortcuts, do it step-by-step. How would you search the database if the user had to type in the data?

android sql - how do you order your sql query by multiple columns

I am currently working on an Android project in Eclipse and i am having problems with my SQL query.
I am trying to order the query by more than two columns, currently i am doing it by KEY_DAY_ID but i want to also do it by KEY_START_TIME, but i can't get it to work
my query currently looks like this:
Cursor cursor = db.query(TABLE_SESSION, new String[] {KEY_ID, KEY_MODULE_CODE,
KEY_DAY_OF_WEEK, KEY_START_TIME, KEY_DURATION, KEY_SESSION_TYPE, KEY_ROOM},
null, null, null, null, KEY_DAY_ID + " ASC");
Please let me know your thoughts. Thank you in advance!
The last parameter in db.query() method is the order by clause (without the "order by"). All you need to do is separate both columns by a ",". So it would look like:
Cursor cursor = db.query(TABLE_SESSION, new String[] {KEY_ID, KEY_MODULE_CODE,
KEY_DAY_OF_WEEK, KEY_START_TIME, KEY_DURATION, KEY_SESSION_TYPE, KEY_ROOM},
null, null, null, null, KEY_DAY_ID + " ASC, " + KEY_START_TIME + " ASC");
This works for me
SQLiteCursor cursor = (SQLiteCursor) db.query(DbHelper.TIMES, colmn, null, null, null, null, DbHelper.TABLE_DAY + " ASC, " + DbHelper.TABLE_LECTURE_NO + " ASC",null);
Also you can do it in select line like this:
Cursor data = ddbb.rawQuery("SELECT * FROM vacations ORDER BY NAME ,MONTH , date ",null);
in previous code the first probability for the first column "NAME" then will start arrange by the Second probability "MONTH" then the third "date".....
which mean working in series
Or:
Cursor data = ddbb.rawQuery("select * from vacations where NAME = ? ORDER BY MONTH AND date ",new String[]{ns});
in previous code by using "AND" the two conditions are working together in parallel

How to filter the results of content resolver in android?

I would like to get user contacts and then append some kind of regular expression and append them to a list view. I am currently able to get all the contacts via
getContentResolver().query(People.CONTENT_URI, null, null, null, null);
and then pass them to a custom class that extends SimpleCursorAdapter.
So I would like to know how to get only the contacts that match a regular expression and not all of users contacts.
Instead of
getContentResolver().query(People.CONTENT_URI, null, null, null, null);
you should use something like
final ContentResolver resolver = getContentResolver();
final String[] projection = { People._ID, People.NAME, People.NUMBER };
final String sa1 = "%A%"; // contains an "A"
cursor = resolver.query(People.CONTENT_URI, projection, People.NAME + " LIKE ?",
new String[] { sa1 }, null);
this uses a parameterized request (using ?) and provides the actual values as a different argument, this avoids concatenation and prevents SQL injection mainly if you are requesting the filter from the user. For example if you are using
cursor = resolver.query(People.CONTENT_URI, projection,
People.NAME + " = '" + name + "'",
new String[] { sa1 }, null);
imagine if
name = "Donald Duck' OR name = 'Mickey Mouse") // notice the " and '
and you are concatenating the strings.
You can query the content provider with sql type input, the Query method is just a wrapper for an sql command.
Here is an example where I query for a Contacts name given a particular number
String [] requestedColumns = {
Contacts.Phones.NAME,
Contacts.Phones.TYPE
};
Cursor contacts = context.getContentResolver().query(
Contacts.Phones.CONTENT_URI,
requestedColumns,
Contacts.Phones.NUMBER + "='" + phoneNumber + "'",
null, null);
Note that instead of null I have parameters that build up the sql statement.
The requestColumns are the data I want to get back and Contacts.Phones.NUMBER + "='" + phoneNumber + "'" is the Where clause, so I retrieve the Name and Type where the Phone Number matches
You should be able to put a legal SQLite WHERE clause as the third argument to the query() method, including a LIKE, but there's no native REGEXP function in SQLite and Android doesn't seem to let you define your own. So depending how complex your needs are, a set of other SQLite conditions and LIKE expressions might do the trick.
See the documentation on the query method under ContentResolver and SQLite expressions.
Actually REGEXP with Calllog Content Provider works (means that regexp() function is defined for that content provider's Database https://sqlite.org/lang_expr.html#regexp)! But it is very slow: ~15 sec across ~1750 records.
String regexp = "([\\s\\S]{0,}" +
TextUtils.join("||[\\s\\S]{0,}", numbers) +
")";
cursor = context.getContentResolver().query(
CallLog.Calls.CONTENT_URI,
null,
CallLog.Calls.NUMBER + " REGEXP ?",
new String[]{regexp},
CallLog.Calls.DATE + " DESC"
);

Categories

Resources