I'm trying to fill in a two-dimensional array, with data from my DB SQLite. But the following happens:
It's my first time with SQLite, by the way, and I was trying to find out if there was something like a "Result Set" or a "Data Table" ... and I found the so-called "Cursor". Ok, I started using it ... inserting a single row in each table (all normal) but now when I insert another row in my subject table, the application crashes when I try to navigate in the cursor.
E/CursorWindow: Failed to read row 6, column 6 from a CursorWindow which has 12 rows, 6 columns.
My table is only made up of 6 columns, and as for the data, the same application shows me that it has 2 rows, but for some reason it only reads the data from the first row and the other rows not.
public String[][] getMaterias(){
String[][] materias = new String[rows][6];
Cursor cursor = admin.selectLog(DBScheme.Tabla_Materias);
cursor.moveToFirst();
try {
for(int f = 0; f < rows; f++){
for(int c = 0; c < 6; c++){
materias[f][c] = cursor.getString(cursor.getPosition());
cursor.moveToNext();
}
}
}catch (IllegalStateException ex){
ex.printStackTrace();
}
return materias;
}
I doubt very much that I have to do something like change the version of the database, since I have not touched the schema of the DB, only the only thing I have done was add another row of data. How I can solve this guys?
E/CursorWindow: Failed to read row 6, column 6 from a CursorWindow
which has 12 rows, 6 columns.
The above message is quite explantory, but you need to think in terms of offsets. That is you have a Cursor with 12 rows and 6 columns (from a CursorWindow which has 12 rows, 6 columns).
That means that you can use offsets 0 to 5 for the columns and that there is no column 6 (offset).
Using position as the column index, as per materias[f][c] = cursor.getString(cursor.getPosition()); will always result in such an error if the number of rows in the cursor exceeds the number of columns in the table.
You may wish to consider the following as not only a fix for the issue but also as perhaps a more adaptable solution (i.e there is no reliance on fixed/hard coded numbers as the number of rows and the number of columns is determined according to the Cursor)
public String[][] getMaterias(){
Cursor cursor = admin.selectLog(DBScheme.Tabla_Materias);
String[][] materias = new String[cursor.getCount()][cursor.getColumnCount()];
while(cursor.moveToNext())
for(int c = 0; c < cursor.getColumnCount(); c++){
materias[cursor.getPosition()][c] = cursor.getString(c);
}
}
return materias;
}
Perhaps even consider making it even more generic by passing a cursor (any cursor) as per :-
public String[][] getMaterias(Cursor cursor){
String[][] materias = new String[cursor.getCount()][cursor.getColumnCount()];
while(cursor.moveToNext())
for(int c = 0; c < cursor.getColumnCount(); c++){
materias[cursor.getPosition()][c] = cursor.getString(c);
}
}
return materias;
}
I feel very embarrassed to ask something really stupid ... the solution was in my eyes all this time:
I just had to change cursor.getPosition() with the c variable:
for(int f = 0; f < rows; f++){
for(int c = 0; c < 6; c++){
materias[f][c] = cursor.getString(c);
cursor.moveToNext();
}
}
I´m really sooorry....
Related
In a table of my database, I have 7 records.
Now I want to update the records through a WHERE clause.
First, count the records, according to a clause
int pos = 0;
String SQL = "SELECT COUNT(posizione) FROM operatori WHERE posizione>0;";
final Cursor cur = db2.rawQuery(SQL, null);
while (cur.moveToNext()) {
pos = cur.getInt(0);
}
cur.close();
//then, with a for loop, update all the records based on a WHERE clause
for (int i = 1; i <= pos; i++) {
ContentValues cv1 = new ContentValues();
cv1.put(OperatoriTable.POSIZIONE, i);
db2.update(OperatoriTable.TABLE_NAME, cv1, OperatoriTable.POSIZIONE + ">0", null);
}
db2.close();
but, for example, if posequals 5, should enter the numbers 1,2,3,4,5. Instead, it is always inserted 1. Where am I wrong?
Your update statement probably updates multiple rows at once.
Each time you call db2.update in the for loop, it probably overwrites all rows where posizione>0 with the value currently in cv1.
Please check following code:
List<Database> zaznamy = new ArrayList<Database>();
String selectQuery = "SELECT X FROM Data WHERE LEVEL_1 =-24 AND LEVEL_2 =-48 AND LEVEL_3 =-55 AND LEVEL_4 =0";
File dbfile = new File("/sdcard/rtls/Databases/"+DBName );
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
Cursor cursor = db.rawQuery(selectQuery,null);
String bodX="empty";
if (cursor.moveToFirst())
{
do {
Database zaznam = new Database();
zaznam.setX(Integer.parseInt(cursor.getString(10)));
zaznamy.add(zaznam);
} while (cursor.moveToNext());
for (Database cn : zaznamy)
{
Log.d("X: ", Integer.toString(cn.getX()));
bodX = (cn.getX()+ "//").toString();
Log.d("X", bodX);
}
}
It says it Couldn't read row 0, col 10 from CursorWindow. I´ve tested the database with SQLite browser. Database has exactly 1 X at column 10, row 0. SQL query is working correctly I believe. Can someone tell me, why it cant be read? Or where is mistake?
EDIT:
corrected the code to:
do {
Database zaznam = new Database();
zaznam.setX(cursor.getInt(10));
zaznamy.add(zaznam);
} while (cursor.moveToNext());
because of integer value of 10th column, but still no luck. Same error
Your query has only one column in projection - column 'X'. That column has index 0 in query projection so to make your code work change your loop to looks like this:
do {
Database zaznam = new Database();
zaznam.setX(cursor.getInt(0));
zaznamy.add(zaznam);
} while (cursor.moveToNext());
To avoid that kind of problems in the future use following:
cursor.getInt(cursor.getColumnIndexOrThrow("X");
Remember that column index is related to query projection and not the sequence of columns in your database, so for example when you write "select B A C from SOME_TABLE" column B will have index 0 and column A will have index 1 etc. even if in your database they are in alphabetical order A B C.
I was having the same issue. For me. A simple work around may be:
// query database and populate an ArrayList
private void getDataFromDatabase() {
Cursor cursor = dbConnector.getSomeData();
if (cursor.getCount() > 0) {
cursor.moveToFirst();
for(int i = 0; i < cursor.getCount(); i++) {
// get column data from database and add it to ArrayList
anArrayList.add(cursor.getString(cursor.getColumnIndexOrThrow("Attr")));
cursor.moveToNext();
} // end for
} // end if
dbConnector.close();
} // end getDataFromDatabase
WHERE "Attr" is the Attribute/column name you wish to query and the anArrayList is the ArrayList you want to store the data in.
I have a table for groups where every each is flaged, in column is_active either with 0 or 1. My problem is to select all groups where flag is 1, and the thing is, if I have 0 records with 1, works fine, if I have 1 record with 1, works fine, but if more than one is tagged with 1 it always returns only 1 record, one with the smallest id.
Here are the codes:
String query = "SELECT _id FROM groups WHERE is_active = ?";
String[] args = { "1" };
Cursor c = db.rawQuery(query, args);
if (c == null || c.getCount() == 0) {
Log.v("t", "foo");
return null;
} else {
int count = c.getColumnCount();
String[] ids = new String[count];
Log.v("t", "aktywnych group: ------ " + count);
for (int i = 0; i < count; i++) {
c.moveToPosition(i);
ids[i] = String.valueOf(c.getInt(c.getColumnIndex("_id")));
}
return ids;
}
What you see now is just another try, I have tried many different ways to obtain this data, never works.
If you have any ideas how can I fix it I would be greatfull.
It's because your using this :
int count = c.getColumnCount();
According to the official documentation, this method returns the number of COLUMNS of your request. Seeing your query, your asking for only one column : _id. So the result will always be 1, or 0 if it find nothing.
You should use this line instead :
int count = c.getCount();
I am trying to query all the columns in a table into one long text view and/or string. I know this might not be the right way to do things but I have to do this. Correct me if I am wrong, I was under the impression that move next would get the next column in the row:
Cursor c = db.get();
if(c.moveToFirst){
do{
string = c.getString(0);
}while(c.moveToNext);
}
I thought that this would get the first column and display all of its contents instead I get the first column and first row. What am I doing wrong? Is there a better or real way to get this information without using a ListView?
The simple use is:
Cursor cursor = db.query(...);
while (cursor.moveToNext()) {
...
}
moveToFirst is used when you need to start iterating from start after you have already reached some position.
Avoid using cursor.getCount() except if it is required.
And never use a loop over getCount().
getCount is expensive - it iterates over many records to count them. It doesn't return a stored variable. There may be some caching on a second call, but the first call doesn't know the answer until it is counted.
If your query matches 1000 rows, the cursor actually has only the first row. Each moveToNext searches and finds the next match. getCount must find all 1000. Why iterate over all if you only need 10? Why iterate twice?
Also, if your query doesn't use an index, getCount may be even slower - getCount may go over 10000 records even though the query matches only 100. Why loop 20000 instead of 10000?
For clarity a complete example would be as follows which I trust is of interest. As code comments indicated we essentially iterate over database rows and then columns to form a table of data as per database.
Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null,
null);
//if the cursor isnt null we will essentially iterate over rows and then columns
//to form a table of data as per database.
if (cursor != null) {
//more to the first row
cursor.moveToFirst();
//iterate over rows
for (int i = 0; i < cursor.getCount(); i++) {
//iterate over the columns
for(int j = 0; j < cursor.getColumnNames().length; j++){
//append the column value to the string builder and delimit by a pipe symbol
stringBuilder.append(cursor.getString(j) + "|");
}
//add a new line carriage return
stringBuilder.append("\n");
//move to the next row
cursor.moveToNext();
}
//close the cursor
cursor.close();
}
I am coding my loops over the cusror like this:
cursor.moveToFirst();
while(!cursor.isAfterLast()) {
cursor.getString(cursor.getColumnIndex("column_name"));
cursor.moveToNext();
}
That always works. This will retrieve the values of column "column_name" of all rows.
Your mistake is that you loop over the rows and not the columns.
To loop over the columns:
cursor.moveToFirst();
for(int i = 0; i < cursor.getColumnNames().length; i++){
cursor.getString(i);
}
That will loop over the columns of the first row and retrieve each columns value.
moveToNext move the cursor to the next row. and c.getString(0) will always give you the first column if there is one. I think you should do something similar to this inside your loop
int index = c.getColumnIndex("Column_Name");
string = c.getString(index);
cursor.moveToFirst() moves the cursor to the first row. If you know that you have 6 columns, and you want one string containing all the columns, try the following.
c.moveToFirst();
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < 6; i++){
stringBuilder.append(c.getString(i));
}
// to return the string, you would do stringBuilder.toString();
I have a listview and i would like to populate a row with several calculations done on multiple database tables rows winch carry the row id as column (group).
So for example one of my database tables has three rows all of winch have a unique row id for one coloumn and also another column (group) which has the same value for all rows allowing them to be grouped together.
What i would like to do is pass a cursor over each row which has the same value in the column group and do a few things on each row like add,minus,subtract etc. and then add the result from each row to a value which i can then attach to the list view.
How can i go about doing this?
You can put the results in an Array and then do your operations you want on each item. Then you use an arrayAdapter to put the items in it.
public String[][] getResultSetAsArray(Cursor cursor) {
int numberOfColumns = cursor.getColumnCount();
int numberOfRows = cursor.getCount();
String [][] resultSetAsArray = new String[numberOfColumns][numberOfRows];
for (int currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
{
cursor.moveToFirst();
for (int currentRow = 0; currentRow < numberOfRows; currentRow++)
{
resultSetAsArray[currentColumn][currentRow] = cursor.getString(currentColumn);
cursor.moveToNext();
}
}
return resultSetAsArray;
}
This method gives you all the results of a cursor back in a two-dimensional array. If you only have one column, you just use the method and put [0] after it to put it in one array.
Example:
String table = tablename;
String[] columns = {column1, column2};
String orderBy = columnNameToOrder;
Cursor cursor = db.query(table, columns, null, null, null, null, orderBy);
String[] column1Values = dbRetrieval.getResultSetAsArray(tabLabelCursor)[0];
String[] column2Values = dbRetrieval.getResultSetAsArray(tabLabelCursor)[1];
String[][] values = dbRetrieval.getResultSetAsArray(tabLabelCursor); // all the database values in a two-dimensional array.