I can't get data from database using cursor - android

I have make following function for getting data.
public List<Presentation> getSlideMaster() {
List<Presentation> pptList = new ArrayList<Presentation>();
String selectQuery = "SELECT * FROM "
+ Constants.SLIDE_MASTER.slideMaster_Table + " WHERE dm_Id=" + lastDeckID;
SQLiteDatabase db = dbhelper.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor.moveToFirst()) {
do {
Presentation presentation = new Presentation();
presentation.setSlideId(cursor.getString(0));
getSlideID = presentation.getSlideId();
Log.i("string slide id in database helper", "" + presentation.getSlideId());
pptList.add(presentation);
} while (cursor.moveToNext());
}
String selectQuery2 = "SELECT sl_Id FROM "
+ Constants.SLIDE_LAYOUT.slideLayout_Table + " WHERE sm_Id = "
+ getSlideID;
Cursor cursorSL = db.rawQuery(selectQuery2, null);
Log.i("query", ""+selectQuery2);
if(cursorSL.moveToFirst()){
Log.i("getslideLayout function", "");
do{
Log.i("query string 0 ", ""+cursorSL.getString(0));
Presentation presentation = new Presentation();
presentation.setSlideLayoutId(cursorSL.getString(0));
getSlideLayoutId = presentation.getSlideLayoutId();
Log.i("string slide layout id in slideMaster", "" + getSlideLayoutId);
}while(cursorSL.moveToNext());
}
else{
Log.i("No Data Found!!!!!", "");
}
cursor.close();
cursorSL.close();
db.close();
return pptList;
}
I getting data from slideMaster_Table very fine and easily but I can't get data from another query, which is not print any value in Logcat inside of if(cursorSL.moveToFirst()) condition
When I use code in another activity i can get sl_Id very easily.

may below solution solve your problem
use Cursor cursorSL = db.rawQuery(selectQuery2, new String[]{getSlideID});
for
selectQuery2="SELECT sl_Id FROM "+Constants.SLIDE_LAYOUT.slideLayout_Table + " WHERE sm_Id = ?";

My speculation is that you have troubles constructing the second query. Basically it is never a good idea to construct database queries like you do. The android database API is providing more accurate interface for that. Rewrite your second part of program to:
String [] selectArgs = {getSlideID};
String selectQuery2 = "sm_Id = ?";
Cursor cursorSL = db.query(Constants.SLIDE_LAYOUT.slideLayout_Table, null,
selectQuery2, selectArgs, null, null, null, null);
Note that the fourth parameter of query is meant for substitution of where arguments, it is String[] and all the array members are substituted in sequence in the places of ? in the query string.
I think you might be facing problem with constructing the query.
PS: You are also misusing the log tags:
Log.i("No Data Found!!!!!", "");
Should actually be Log.i("TAG", "No Data Found!!!!!");
The first parameter is log tag and is supposed to be used for grouping related log messages, in your case you print every message in its own group, which does not make much sense.
I know this note will not solve your immediate problem, but I am pointing it out, so that you will know it for the future (I also suffer from seeing colleagues of mine learning from SO wrong practises like that one).

Related

Android Studio - Value must be ≥ 0

I am getting an error in Android Studio to do with my Cursor.
I have the following line in my code
String data = cursor.getString(cursor.getColumnIndex(columnIndex));
columnIndex is being passed into the method.
This part cursor.getColumnIndex(columnIndex) produces the following error
Value must be ≥ 0
Its happening in my DBHelper class and also my recycler adapter when it uses a cursor too.
It shows up as an error in red but the app still builds and runs without issue.
Any ideas?
Thanks for any help.
Update 22-Sep-21
I'm adding some code as requested and also how i have got around this error. Not sure if its the best way though.
So the method im using is this....
public String getTripInfo(String tableName, int tripNo, String columnIndex){
String data = "";
// Select all query
String selectQuery = "SELECT * FROM " + tableName + " WHERE " + TRIP_DETAILS_TRIP_NUMBER + "=" + tripNo;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// Looping through all rows and adding to list
if(cursor.moveToFirst()){
do{
data = cursor.getString(cursor.getColumnIndex(columnIndex));
} while(cursor.moveToNext());
}
// Closing connections
cursor.close();
db.close();
//Returning number plates
return data;
}
The error is in the do while loop. The part in red is "cursor.getColumnIndex(columnIndex))"
The way i have gotten around this error is using the following code instead
public String getTripInfo(String tableName, int tripNo, String columnIndex){
String data = "";
// Select all query
String selectQuery = "SELECT * FROM " + tableName + " WHERE " + TRIP_DETAILS_TRIP_NUMBER + "=" + tripNo;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// Looping through all rows and adding to list
if(cursor.moveToFirst()){
do{
int index = cursor.getColumnIndex(columnIndex);
data = cursor.getString(index);
} while(cursor.moveToNext());
}
// Closing connections
cursor.close();
db.close();
//Returning number plates
return data;
}
I had an error like this.
My solution : change method getColumnIndex into getColumnIndexOrThrow.
The problem is that cursor.getColumnIndex() can return -1, you're passing it as a direct parameter, and the cursor getters need a column index gte 0. The getters' parameter is annotated with #IntRange(from = 0) which is why lint marks it as an error.
So, even though you might have built your project such that it would never produce an invalid column index, the fact that such a possibly could exist is why lint is tagging it.
Your code revision only avoids the issue. It would be best to use cursor.getColumnIndexOrThrow() or test index for gte 0.
You can get away with your changes since you know more about your project than lint does, it just isn't the best practice.
Use This Method Proper Work :-
#SuppressLint("Range") Strong name = cursor.getString(cursor.getColumnIndex(indexNumber));

Updating a single column is creating sqlite syntax error

I'm not sure what I'm doing wrong, but I'm trying to update a single integer value in a column of a table to 1 from 0. When creating the database, I set all values of the column to zero using:
for (int i = 0; i < setups.length; i++) {
ContentValues values = new ContentValues();
values.put(JokeDbContract.TblJoke.COLUMN_NAME_SETUP, setups[i]);
values.put(JokeDbContract.TblJoke.COLUMN_NAME_PUNCHLINE, punchlines[i]);
values.put(JokeDbContract.TblJoke.COLUMN_NAME_USED, 0);
db.insert(JokeDbContract.TblJoke.TABLE_NAME, null, values);
}
Then, in the actual activity, I'm doing:
private void findNewJoke() {
JokeDb jokeDb = JokeDb.getInstance(this);
SQLiteDatabase theDb = jokeDb.getDB();
String selection = JokeDbContract.TblJoke.COLUMN_NAME_USED + "=" + 0;
// Query database for a joke that has not been used, update the fields
// theJoke and thePunchline appropriately
String[] columns = {JokeDbContract.TblJoke._ID,
JokeDbContract.TblJoke.COLUMN_NAME_PUNCHLINE,
JokeDbContract.TblJoke.COLUMN_NAME_SETUP,
JokeDbContract.TblJoke.COLUMN_NAME_USED};
Cursor c = theDb.query(JokeDbContract.TblJoke.TABLE_NAME, columns, selection,
null, null, null, null);
if (c.moveToFirst() == false) {
Toast.makeText(this, R.string.error_retrieving_joke, Toast.LENGTH_LONG).show();
Log.e(getString(R.string.app_name),"No jokes retreived from DB in JokeActivity.findNewJoke()!");
}
else {
ContentValues values = new ContentValues();
theSetup = c.getString(c.getColumnIndexOrThrow(JokeDbContract.TblJoke.COLUMN_NAME_SETUP));
thePunchline = c.getString(c.getColumnIndexOrThrow(JokeDbContract.TblJoke.COLUMN_NAME_PUNCHLINE));
String updateSelection = JokeDbContract.TblJoke.COLUMN_NAME_SETUP + "=" + theSetup;
values.put(JokeDbContract.TblJoke.COLUMN_NAME_USED, 1);
theDb.update(JokeDbContract.TblJoke.TABLE_NAME, values, updateSelection, null);
}
}
I'm getting an error on the update:
java.lang.RuntimeException: .... while compiling: UPDATE jokes SET used=?
WHERE setup=Why do programmers always mix up Halloween and Christmas?
It seems as though I'm not getting an actual value set for the used column. What the program ultimately does is cycle through jokes where used=0, then sets used to 1 when it has been viewed. So the query only pulls those jokes that aren't used yet. I have a feeling I'm missing something simple, one can hope.
I think you are having problems with quotation marks.
Example:
String updateSelection = JokeDbContract.TblJoke.COLUMN_NAME_SETUP + "=\"" + theSetup + "\"";
However, the recommended way to do this, would be:
theDb.update(JokeDbContract.TblJoke.TABLE_NAME, values, JokeDbContract.TblJoke.COLUMN_NAME_SETUP + " = ?", new String[] { theSetup });
It is better to use field = ?, because this helps sqlite cache queries (I believe).

Android: Having trouble updating a row in a database after determining what row I need to update

I have a table that contains a list of devices with catagories like type, manufacturer and model and a device ID. Another table called system uses the device id to point to the table with the devices. I have a edit system function that I am trying to get working where I can edit the device id field in a record on the system table to change which device in the devices table I am pointing too. I run the update command and it looks like it should work but the row does not get updated. Does anyone know what I am doing wrong?
Here is my update code routine.
SQLiteDatabase db = dbHelper.getWritableDatabase();
String UpdateDeviceName = txtEditDeviceName.getText().toString();
String UpdateDeviceIP = txtEditDeviceIP.getText().toString();
//get the new device id based off of the three spinner values
String dbQuery = "SELECT * FROM " + dbHelper.Devices_Table + ";";
Cursor c = db.rawQuery(dbQuery, null);
if (c.getCount() > 0)
{
while (c.moveToNext())
{
int iColumnID = c.getColumnIndex(dbHelper.Attribute_Device_ID);
int iColumnDeviceType = c.getColumnIndex(dbHelper.Attribute_Device_Type);
int iColumnDeviceManufacturer = c.getColumnIndex(dbHelper.Attribute_Device_Manufacturer);
int iColumnDeviceModel = c.getColumnIndex(dbHelper.Attribute_Device_Model);
String CheckDeviceType = c.getString(iColumnDeviceType);
if (CheckDeviceType.equals(DeviceType))
{
String CheckDeviceManufacturer = c.getString(iColumnDeviceManufacturer);
if (CheckDeviceManufacturer.equals(DeviceManufacturer))
{
String CheckDeviceModel = c.getString(iColumnDeviceModel);
if (CheckDeviceModel.equals(DeviceModel))
{
DeviceID = c.getString(iColumnID);
}
}
}
}
}
db.close();
c.close();
db = dbHelper.getWritableDatabase();
//with the device ID update the system
dbQuery = "UPDATE " + dbHelper.System_Table + " SET " + dbHelper.Attribute_Device_ID + " = " + DeviceID + ", " +
dbHelper.Attribute_Device_Name + " = '" + UpdateDeviceName + "', " +
dbHelper.Attribute_Device_IP + " = '" +
UpdateDeviceIP + "' WHERE " + dbHelper.Attribute_Device_ID + " = " + OrginalDeviceID + ";";
c = db.rawQuery(dbQuery, null);
Log.d("Database Dump", "Edit Device Query: " + dbQuery);
c.close();
db.close();
You closed the DB after the search:
db.close();
leave out this line, since the DB helper code prefers to keep the DB open until it is no longer used (use dbHelper.close() to close the DB when you are done with it).
The same applies after the update.
First of all any rawQuery statement must not contain the trailing semicolon! See the documentation of SQLiteDatabase.
Also you always must close cursors before closing the database. And you have to close the db when you get a new one for each query. Otherwise the system at some point later on will throw exceptions. While those only will be logged and do not cause a Force Close, you should still care about proper resource management.
Finally you should use the updateWithOnConflict method instead with using CONFLICT_REPLACE as the conflictAlgorithm. This simply ignores any UNIQUE constraints and overwrites conflicting rows. So be careful. If you do not want to overwrite existing rows you have to make sure that a constarint violation isn't causing your problem.
I found the answer. FIrst off I want to thank Henry and Wolfram Rittmeyer. You guys where very helpful. :)
For whatever reason the android SQLite does not like to use the update statement in raw sql query form. In researching what Wolfram Rittmeyer said about updateWithConflict I found the update method in the SQLiteOpenHelper object which my dbHelper extends. When I switched to that method I was able to update the database. My where conditions have been expanded on to include the device name as well in the event that the system has more then one device make and model of the same type and only one has to change.
For reference the working code to update the database is the following. I'm only posting the changed portion of the code. Everything in the if (c.getCount() > 0) block and above is unchanged.
c.close();
dbHelper.close();
db = dbHelper.getWritableDatabase();
//with the device ID update the system
ContentValues values = new ContentValues();
values.put(dbHelper.Attribute_Device_ID, DeviceID);
values.put(dbHelper.Attribute_Device_Name, UpdateDeviceName);
values.put(dbHelper.Attribute_Device_IP, UpdateDeviceIP);
String Where = dbHelper.Attribute_Device_ID + " = " + OrginalDeviceID + " AND " + dbHelper.Attribute_Device_Name + " = '" + OrginalDeviceName + "'";
db.update(dbHelper.System_Table, values, Where, null);
c.close();
dbHelper.close();
finish(); //this exits the activity and goes back to the calling activity

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: Deleting specific row in database

Sorry if this seems obvious. I'm trying to write a method to delete a row from a String showId. What would be the best way, and can Cursors only be used for Selects or also for Deletes and Updates?
These are the two methods I'm at so far:
public int deleteShowById1(String showId){
Cursor cursor = db.rawQuery("DELETE FROM tblShows WHERE showId = '" + showId+"'", null);
if (cursor.moveToFirst()) {
return 1;
} else
return -1;
}
public int deleteShowById2(String showId) {
String table_name = "tblShows";
String where = "showId='"+showId+"'";
return db.delete(table_name, where, null);
}
As we know from mysql query, it is same here in android.
String query = "DELETE FROM " +TABLE_NAME+ " WHERE " + COLUM_NAME+ " = " + "'"+VALUE +"'" ;
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL(query);
db.close();
VALUE may or may not have single quotation depending on datatype.
I tend to use the second method (db.delete), as I think using rawQuery is frowned upon.
If you do a select, then loop through the cursor to do updates or deletes, that would make sense, but to pass a cursor to do the delete or update doesn't make sense to me, as the program won't know how to parse the cursor results to get the correct fields.

Categories

Resources