im trying to update specific row but no luck.
Im first time working with sqlite, maybe its true im confused with column/row
In ideal i want update text in field with name MESSAGE_HISTORY(id=5)
Same way and code works for field Item0 (id = 1)
public static void updateHistory(ArrayList<MessageModel> models, String id) {
if (database != null) {
Cursor c = database.query(TDatabaseHelper.DATABASE_TABLE,null,null, null, null, null, null);
if (c.moveToFirst()) {
do {
int index1 = c.getColumnIndex(MESSAGE_HISTORY);//return position 5
ContentValues data = new ContentValues();
data.put(MESSAGE_HISTORY, DatabaseHelper.chatHistoryModelsConvert(models, id).toString());
long k = database.update(TDatabaseHelper.DATABASE_TABLE, data, "id=" + index1, null);
DBLogger.w("DATABASE UPDATE STATUS = "+k);
}while(!c.moveToFirst());
}else {
DBLogger.d("Error");
}
}
}
K always return 0
Any help ?
[UPD]
public static void CreateDB() {
if (database != null) {
Cursor c = database.query(TDatabaseHelper.DATABASE_TABLE, null, null, null, null, null, null);
if (!c.moveToFirst()) {
cv.put(TDatabaseHelper.ITEM0, "Item0"); // <---- this item update very good index = 1
cv.put(TDatabaseHelper.MESSAGE_HISTORY, "history"); <-- cant update, index = 5;
cv.put(TDatabaseHelper.ITEM1, "item1");
cv.put(TDatabaseHelper.ITEM2, "item2");
cv.put(TDatabaseHelper.ITEM3, "item3");
long rowID = database.insert(TDatabaseHelper.DATABASE_TABLE, null, cv);
DBLogger.i("row inserted, ID = " + rowID);
}
}
}
[UPD]
this not help :(
String[] args = new String[]{""+index1}; ??database.update(TDatabaseHelper.DATABASE_TABLE, data, "id=?", args);
The following line gives you the index of the column named MESSAGE_HISTORY but it does not give you the value.
int index1 = c.getColumnIndex(MESSAGE_HISTORY);//return position 5
As a result of this, your line
long k = database.update(TDatabaseHelper.DATABASE_TABLE, data, "id=" + index1, null);
updates a row that has an id of "5" and it seems that it does not exist. You need to get the value in column 5, so do something like the following:
String messageValue = c.getString(index1);
long k = database.update(TDatabaseHelper.DATABASE_TABLE, data,
MESSAGE_HISTORY + " = ?", new String[] {messageValue});
It is better to use the whereArgs here since just appending messageValue may cause problems. See the update documentation regarding the whereClause and whereArgs.
In any case, slap the debugger on that last line to see exactly what you are passing to the update method. You may be surprised.
Related
I keep getting this error message: "Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0" in my code.
I have already referenced the following links, but none of them have worked:
Android cursor out of bounds exception
Cursor index out of bounds
Cursor Index Out Of Bounds Error Android?
cursor index out of bounds exception
public Product getProduct(int id) {
db = this.getReadableDatabase();
Cursor cursor = db.query(
TABLE_NAME,
null,
COLUMN_ID + " = ?",
new String[] { Integer.toString(id)},
null, null, null, null);
Product product = new Product();
cursor.moveToFirst();
if (cursor != null) {
product.setID(cursor.getInt(0));
product.setName(cursor.getString(1));
product.setSize(cursor.getDouble(2));
product.setHp(cursor.getDouble(3));
product.setCategory(cursor.getString(4));
product.setPowerType(cursor.getString(5));
product.setExplosionProof(cursor.getInt(6));
product.setRPM(cursor.getInt(7));
product.setBypassPSI(cursor.getInt(8));
product.setGPM(cursor.getInt(9));
product.setPrice(cursor.getDouble(10));
cursor.close();
}
db.close();
return product;
}
And here are my constants:
private static final String TABLE_NAME = "Products";
private static final String COLUMN_ID = "'_id'";
I would greatly appreciate any help.
Now, it won't go into the if-loop. I got that query model straight from another stack overflow question.
It is very likely that the cursor is empty, as such you need to ascertain why. It could be that there is no underlying data or it could be that the cursor where clause is excluding all data. From what you have provided it is impossible to determine why.
I would suggest removing the where clause to see if this changes matters.
i.e. instead of
Cursor cursor = db.query(
TABLE_NAME,
null,
COLUMN_ID + " = ?",
new String[] { Integer.toString(id)},
null, null, null, null);
use :-
Cursor cursor = db.query(
TABLE_NAME,
null,
null,
null,
null, null, null, null);
This would return all rows from the cursor, if this works then the issue is with the where clause (3rd and 4th parameters passed to db.query). If it doesn't resolve the issue then it is likely that the table itself has no rows.
You could circumvent the CursorIndexOutOfBoundsException by using :-
if (cursor.getCount() > 0) {
cursor.moveToFirst();
product.setID(cursor.getInt(0));
product.setName(cursor.getString(1));
product.setSize(cursor.getDouble(2));
product.setHp(cursor.getDouble(3));
product.setCategory(cursor.getString(4));
product.setPowerType(cursor.getString(5));
product.setExplosionProof(cursor.getInt(6));
product.setRPM(cursor.getInt(7));
product.setBypassPSI(cursor.getInt(8));
product.setGPM(cursor.getInt(9));
product.setPrice(cursor.getDouble(10));
} else {
// setup to return a product not found
}
cursor.close();
However, this won't fix the underlying issue that the cursor is not returning any rows.
You could use something like the following to get more information regarding the cursor (running with the cursor selecting all rows as per change above). This should work for any cursor :-
int rowcount = cursor.getCount();
String colnames = "";
for (String columns : cursor.getColumnNames()) {
colnames = colnames +
"Column Index=" +
Integer.toString(cursor.getColumnIndex(columns)) +
" Name=>" +
columns +
"< ";
}
Log.d("DBCHK","Table has " + Integer.toString(rowcount) + " rows. With columns:- " + colnames);
String values;
while (cursor.moveToNext()) {
values = "";
for (int i = 0; i < cursor.getColumnCount(); i++) {
values = values +
"Column = " +
cursor.getColumnName(i) +
" Index=" +
Integer.toString(i) +
" Value=" + cursor.getString(i) + ": ";
}
Log.d("DBCHK",values);
}
This would write data to the log along the lines of :-
D/DBCHK: Table has 2 rows. With columns:- Column Index=0 Name=>_id< Column Index=1 Name=>myfloat<
D/DBCHK: Column = _id Index=0 Value=null: Column = myfloat Index=1 Value=56.7897:
D/DBCHK: Column = _id Index=0 Value=null: Column = myfloat Index=1 Value=87.7655:
There will be a line per row, these preceded with a line listing the number of rows and what the columns are.
I have to get two last elements from table (or just id). My element's id is increased but not increment (next value is always larger but it is possible that more than 1 - elements are created by someone else and I am not supposed to modified them).
I know how to id it for last one:
public Long getLastDay(){
Cursor cursor= mDatabase.query(DatabaseHelper.TABLE_DAYS, new String[]{"MAX(" + DatabaseHelper.COLUMN_DAY_ID + ")"}, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
return (cursor.getLong(0));
}
return Long.parseLong("0");
}
For example for ids:
1 4 7 11 14 15 19 25 28
I want to get 28 (it works) and 25.
How is it possible to get the second value?
#EDIT:
My code is:
public Long getSecondLastDay(){
Cursor cursor= mDatabase.rawQuery("SELECT "+DatabaseHelper.COLUMN_DAY_ID+" FROM " + DatabaseHelper.TABLE_DAYS+ " LIMIT 2", null);
if (cursor != null) {
cursor.moveToFirst();
return (cursor.getLong(0));
}
return Long.parseLong("0");
}
Sort the days in the reverse direction, and then just take the first two rows:
Cursor cursor = mDatabase.query(DatabaseHelper.TABLE_DAYS,
new String[]{ DatabaseHelper.COLUMN_DAY_ID },
null, null, null, null,
DatabaseHelper.COLUMN_DAY_ID + " DESC",
"2");
long secondToLastDay = 0, lastDay = 0;
if (cursor.moveToFirst()) {
lastDay = cursor.getLong(0);
if (cursor.moveToNext())
secondToLastDay = cursor.getLong(0);
}
use cursor.moveToLast and then cursor.moveToPreviuous
I'm storing a number of objects for my app in an SQLite Database. The class for these objects has a constructor that takes a Cursor object, passed in from the Database class. Example:
public MyClass(Cursor cursor) {
this.id = cursor.getString(cursor.getColumnIndex(MyDatabase.KEY_ROWID));
this.nickname = cursor.getString(cursor.getColumnIndex(MyDatabase.KEY_NICKNAME));
...and so on.
However I've noticed that at random times I've been getting a crash when getColumnIndex for the ID column returns -16. (And if I comment out that line, whichever the first column I try to access is, it will also return -16). I've added some extra logging around it but it hasn't helped as it seems like the columns are fine:
public MyClass(Cursor cursor) {
Log.i("TEST", Column names are: " + Arrays.toString(cursor.getColumnNames()));
Log.i("TEST", Making object, id column index is " + cursor.getColumnIndex(MyDatabase.KEY_ROWID));
Which prints:
Column names are: [_id, nickname...]
Making object, id column index is -16
So it sees like everything should be fine, anyone got any clue why everything could be getting so messed up while reading from the Cursor?
EDIT: Here's how I'm getting the cursor, this is a method in the database class:
public MyObject getMyObject(String id) {
MyObject objectFound = null;
String[] whereArgs = { id };
Cursor cursor = db.query(true, getTableName(), null, WHERE_EQUALS, whereArgs, null, null, null, null);
if(cursor.moveToFirst()) {
//Should only return 1 entry from DB
while(cursor.isAfterLast() == false) {
objectFound = new MyObject(cursor);
cursor.moveToNext();
}
}
cursor.close();
return objectFound;
}
I have table ( id , text) and I need to swap two values in columns like this:
Before.
1 one.
2 two.
3 three.
After ( 1 and 3 swap)
1 three
2 two
3 one
To update each row, you need something like this:
void updateMyTableText (MyTableRow row)
{
ContentValues values = new ContentValues();
values.put ("text", MyTableRow.text);
String where = "id = ?";
String[] whereArgs = new String[1];
whereArgs[0] = Long.toString (row.id);
getDb().update ("MyTable", values, where, whereArgs);
}
where MyTableRow is
class MyTableRow
{
long id;
String text;
}
You'll also need some queries to get the "text" for rows 1 and 3.
Here's one way to do a query:
long getId (String text)
{
// do the query
String query = "select id from MyTable where text = ? ";
String[] args = new String[1];
args[0] = text;
Cursor cursor = getDb().rawQuery (query, args);
if (cursor == null)
throw new IllegalStateException ("cursor is null");
try
{
// get the results
if (!cursor.moveToNext())
return -1; // row not found
long id = cursor.getLong (0);
return id;
}
finally
{
cursor.close();
}
}
Are you trying to change the values in the rows themselves? Most databases systems don't let you arbitrarily swap values since there is an assumption that they are permanently associated. You could issue UPDATE commands to permanently modify the values, but doing this temporarily will probably be an issue handled once the data is returned.
UPDATE table_name
SET text=three
WHERE id=1;
UPDATE table_name
SET text=one
WHERE id=3;
// Assuming id1 < id2
void swap(id1,id2)
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues CV = new ContentValues();
// First get the 2 rows
Cursor res = db.rawQuery("SELECT COLUMN_NAME FROM "+ TABLE_NAME +" WHERE ID IN ("+id1+","+id2+") ORDER BY ID ASC",null);
res.moveToFirst();
CV.put("COLUMN_NAME",res.getString(0));
//Update 1st row with 2nd item
db.update(TABLE_NAME,CV,"ID = ?",new String[]{id2+""});
res.moveToNext();
CV.put("COLUMN_NAME",res.getString(0));
//Update 2nd row with 1st item
db.update(TABLE_NAME,CV,"ID = ?",new String[]{id1+""});
}
Hope it helps!!
I have a selection of sqlite entries displayed in a ListView, and I have their primary keys in a parallel array. When a user selects an item, the item is sent to an Editor activity (so the user can edit that entry). The way I programmed it, the Editor activity class retrieves the entry from the database using its row number (meaning position), using the Cursor's moveToPosition function.
How can I use an entry's primary key to find out its row number?
EDIT :
I have found a solution, wherein I first retrieve a selection of entries from the database, and then go back and retrieve the primary keys of those entries. I store the entries in one array, and the primary keys in another array.
Hopefully you'll be able to give clearer responses after seeing the code. I'm looking for a more elegant solution, although this seems to work.
Here is the relevant code.
CalendarMenu.java
#Override
public void onCreate(Bundle savedInstance){
incomeManager = new SQLManagerIncome(this);
incomeManager.open();
//This method (see below) gets all of the SQLite entries between two dates
incomeArray = incomeManager.getDatedEntriesString(
currentDay.getTimeInMillis(),
nextDay.getTimeInMillis());
//This method (see below) gets the primary keys of all the entries retrieved
//in the previous method
incomeArrayKeys = incomeManager.getDatedKeys(
currentDay.getTimeInMillis(),
nextDay.getTimeInMillis());
incomeManager.close();
// Sending the SQL info to the ListViews
incomeAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, incomeArray);
dayList.setAdapter(incomeAdapter);
}
#Override
public void onItemClick(AdapterView<?> listView, View view, int pos, long id) {
Bundle basket = new Bundle();
// we need to send the position of an entry inside the entire database to the
// Editor class. So we'll use the primary key of an entry to retrieve its position.
switch (listView.getId()) {
case R.id.dayList:
int entryPos = 0;
//incomeArrayKeys holds all of the primary keys. It is a parallel
//array to the array that is displayed in the listview
//(using a standard ArrayAdapter)
incomeManager.open();
entryPos = incomeManager.findPosByKey(incomeArrayKeys[pos]);
incomeManager.close();
basket.putLong("index", entryPos);
Class dayClass;
try {
dayClass = Class.forName("com.shulim.maaser.EditIncome");
Intent dayIntent = new Intent(CalendarMenu.this, dayClass);
dayIntent.putExtras(basket);
startActivityForResult(dayIntent, 0);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
}
SQLManagerIncome.java
public String[] getDatedEntriesString(Long firstDay, Long lastDay){
String[] columns = new String[] { KEY_ROWID, KEY_DESCRIPTION,
KEY_AMOUNT, KEY_DATE, KEY_OWED };
String selection = KEY_DATE + " >=" + firstDay + " AND " + KEY_DATE
+ "<" + lastDay;
Cursor c = ourDatabase.query(INCOME_TABLE, columns, selection, null, null, null, null);
int iDescription = c.getColumnIndex(KEY_DESCRIPTION);
int iAmount = c.getColumnIndex(KEY_AMOUNT);
ArrayList<String> keys = new ArrayList<String>();
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
Long dateMillis = c.getLong(3);
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(dateMillis);
int mYear = cal.get(Calendar.YEAR);
int mMonth = cal.get(Calendar.MONTH)+1;
int mDay = cal.get(Calendar.DAY_OF_MONTH);
String date = mMonth + "-" + mDay + "-" + mYear;
String result = "Desc: " + c.getString(iDescription)
+ ". Amount: $"
+ c.getString(iAmount) + ". Date: "
+ date + "\n";
keys.add(result);
}
String[] stringDateKeys = new String[keys.size()];
stringDateKeys = keys.toArray(stringDateKeys);
c.close();
return stringDateKeys;
}
public Integer[] getDatedKeys(Long firstDay, Long lastDay) {
String[] columns = new String[] { KEY_ROWID, KEY_DESCRIPTION,
KEY_AMOUNT, KEY_DATE };
String selection = KEY_DATE + " >=" + firstDay + " AND " + KEY_DATE
+ "<" + lastDay;
Cursor c = ourDatabase.query(INCOME_TABLE, columns, selection, null,
null, null, null);
int iRow = c.getColumnIndex(KEY_ROWID);
ArrayList<Integer> keys = new ArrayList<Integer>();
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
int result = c.getInt(iRow);
keys.add(result);
}
Integer[] intKeys = new Integer[keys.size()];
intKeys = keys.toArray(intKeys);
c.close();
return intKeys;
}
public int findPosByKey(Integer integer) {
String[] columns = new String[] { KEY_ROWID, KEY_DESCRIPTION,
KEY_AMOUNT, KEY_DATE };
Cursor c = ourDatabase.query(INCOME_TABLE, columns, null, null,
null, null, null);
int iRow = c.getColumnIndex(KEY_ROWID);
int position = 0;
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
if (c.getInt(iRow) == integer) {
break;
}
position++;
}
c.close();
return position;
}
The way I programmed it, the Editor activity class retrieves the entry from the database using its row number (meaning position), using the Cursor's moveToPosition function.
You don't need to use the cursor's moveToPosition function. Instead, there's a much better solution: use the primary key that you already have available. The primary key allows a very simple and efficient SQL query that will return only the exact row you want. I don't know your column names, but an example SQL query to load this row would be
SELECT foo, bar, baz
FROM FooBar
WHERE pk = userSelectedPrimaryKey;
where userSelectedPrimaryKey is inserted into the statement via a query builder.
Of course this is just a rough sketch, but the point is that this query will return exactly one row, which is the only row with the primary key value that the user selected. This is simpler, and improves performance because there is no need to iterate through unnecessary rows.
You have mentioned that I have their primary keys in a parallel array.You have an option to retrieve the Primary Key of the item selected from this array by calling int pk= array[position] and passing this value to EditorActivity. In EditorActivity you can easily retrieve the row you want to edit by passing this primary key in where condition of your SQL query like what Adam Mihalcin has mentioned in his answer.
I have found a solution, wherein I first retrieve a selection of entries from the database, and then go back and retrieve the primary keys of those entries. I store the entries in one array, and the primary keys in another array. See the code I that I posted in the question.
I'm looking for a more elegant solution, although this seems to work for now. I'm hoping for something more optimized.