I just want to create simple database, one table with two columns: id, which will be auto incremented and data, so with my target data to store. I created this code, which doesn't return any error but also don't add any data:
database = openOrCreateDatabase ("alldata", 0, null);
try{
database.execSQL("CREATE TABLE cars(_id INTEGER PRIMARY KEY,data INTEGER);");
}
catch(SQLException e){
}
//database.execSQL("INSERT INTO cars(data) values(0);");
database.execSQL("INSERT INTO cars(data) values(1);");
database.execSQL("INSERT INTO cars(data) values(2);");
database.execSQL("INSERT INTO cars(data) values(3);");
database.execSQL("INSERT INTO cars(data) values(4);");
database.execSQL("INSERT INTO cars(data) values(5);");
String[] data={"_id","data"};
Cursor c=database.query(false, "cars", data, null, null, null, null, null, null, null);
int i=0;
if(c.getCount()>0){
c.moveToFirst();
readed[i]=c.getInt(0);
readed[i+1]=c.getInt(1);
i+=2;
}
And when i try to read the "readed" table it only shows two zeros 00:
for(int i=0;i<readed.length;i++){
if(readed[i] != null)
draw_number((int) readed[i],canvas,(float)(0.9*width-i*0.05*width),(float)(0.8*height));
}
Draw number is my methos which is drawing a number on surfaceview, there is nothing wrong with this one. But unfortunetly I do not know, where is a problem with database. As far as i know I did everything ok and it should return:
0 0 1 1 2 2 3 3 4 4 5 5 (because earlier I added one 0 to data column.)
But it only returns 0 0
Any ideas?
You can just clear the Application Data, using 'Manage Apps' --> 'Clear Data' (This would delete all the previously created Databases, Preferences and all that stuff). And again execute the code using AUTOINCREMENT.
database.execSQL("CREATE TABLE cars(_id INTEGER PRIMARY KEY AUTOINCREMENT,data INTEGER);");
The code seems to behave exactly as written.
First you have some code that checks if there is a row in the results. It then proceeds to read the first result, and only the first result (maybe you are mistaking if for while? but in such case you have got moveToFirst wrong, even if you switch if for a while it will only read the first row, again and again) and place it into readed array.
Since readed contains just the numbers from the first row, the second snippet will loop over the whole array but print only the two first numbers (the values that are not null). And this is exactly the result you report.
Perhaps you wanted to write a code that loads all the cursor rows into readed? It would be a loop (not a conditional statement):
while (c.hasNext()) {
c.moveToNext();
readed[i] = c.getInt(0);
readed[i+1] = c.getInt(1);
i += 2;
}
And swallowing exceptions is an offense and an insult to everyone answering your question.
Tendency towards hiding errors instead of solving them is visible in this line of your code:
if(readed[i] != null) {
If it wasn't for the former errors, this code would not be necessary. I believe that the first time you run the loop you got a null pointer exception, and instead of checking the logic of filling the array (what is a null value doing there?!) you just removed the symptoms. This is just like swallowing an exception: shooting the messenger because you don't like some news.
EDIT / UPDATE
As for creating tables, each sqlite database in Android has a version number (a simple int that you can read or write, a fresh database starts with 0), so the low-level way of handling this would be to have something like:
if (database.getVersion == 0) {
// ...create table here...
database.setVersion(1);
}
Most people end using Sqliteopenhelper, as it helps a bit in solving other problems (that you have not hit yet, but probably will) like concurrent access to the database.
you have not used auto increment for your database.? as can be seen in your database
That's the reason you are getting only 1 result.
use drop table and try again
change
for(int i=0;i<readed.length;i++){
to
for(int i=0;i<readed[].length;i++){
Related
Suppose you're trying to get values from several columns of an Android cursor (I'm using SQLite if that matters). You only care about one row, so caching the column indices doesn't make sense. You can try to get each column's value in one line like this:
String value = cursor.getString(cursor.getColumnIndex(columnName));
But how do you detect and handle a case where a column by that name doesn't exist in the cursor?
We know that if that happens, cursor.getColumnIndex(name) will return -1. But then what will cursor.getString(-1) do? Can you use try, and catch any exception thrown? It's not clear ... the documentation says,
The result and whether this method throws an exception when the column value is null or the column type is not a string type is implementation-defined.
But it doesn't say anything about exceptions or other specified behavior for a columnIndex of -1.
My testing on a few devices indicates that you get this exception:
java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.
Make sure the Cursor is initialized correctly before accessing data from it.
Can we count on that exception being thrown?
Another way to do it is to check the index returned by getColumnIndex() before calling getString(columnIndex):
columnIndex = cursor.getColumnIndex(columnName);
if (columnIndex < 0) {
// handle absence of column
} else {
value = cursor.getString(columnIndex);
}
But using that many lines per column seems verbose, and violates the DRY principle, lending itself to careless errors in the code.
I wouldn't mind the repetition if we could extract that code into a separate method to be called for each column. But I don't see any simple way to do it, because the columns can have different types. (We could subclass CursorWrapper and implement getInt(), getString(), etc. to do the checking we want, thus confining the repetition to a specialized utility class. Is that the best we can do?)
Another approach would be using getColumnIndexOrThrow() instead of getColumnIndex(). That would allow you to skip the step of saving the value of columnIndex and testing it, because you can count on an exception being thrown if columnIndex is -1 (and catch it). But that doesn't perform very well:
If you're not sure if a column will exist or not use getColumnIndex(String) and check for -1, which is more efficient than catching the exceptions.
Any other ideas? Any thoughts on the above ideas?
Is there a concise, predictable way to get a column value from a
cursor?
I'd say yes but that would be according to good design methodology which would largely if not completely eliminate guessing/not knowing a column name. That is the column names would be known before the Cursor is created.
However, there could be situations where the column name, even if correct, could result in unanticipated results. For example where a Cursor with joined tables which had the same column name (e.g. the often used _id column) or perhaps going to the realms of insanity something like SELECT _id, _id, _id FROM cards . In such cases renaming column name via an AS clause would be the solution.
But how do you detect and handle a case where a column by that name
doesn't exist in the cursor?
Again, as above, a well designed project would likely fully negate the chance of this happening. If not, then use of the Cursor getColumnCount and getColumnName methods could be used to circumvent the -1, IllegalStateException condition e.g.
public boolean isColumnInCursor(String columName, Cursor csr) {
for (int i=0; i < csr.getColumnCount(); i++) {
if (csr.getColumnName(i).toLowerCase().equals(columName.toLowerCase())) {
csr.close();
return true;
}
}
csr.close();
return false;
}
An example usage being :-
Cursor csr = ex001db.getAisleAndShopsWithUniqueIDColumns();
String test_column = "Fred";
if (!ex001db.isColumnInCursor("Fred", csr)) {
Log.d("OUCH","Column " + test_column + " not in Cursor");
}
test_column = DBHlpr001.AISLENAMECOLUMN;
if (!ex001db.isColumnInCursor(test_column, csr)) {
Log.d("OUCH","Column " + test_column + " not in Cursor");
} else {
Log.d("NOT OUCH","Column " + test_column + " is in Cursor");
}
csr.close();
with output from the above being :-
09-20 13:25:35.163 4217-4217/? D/OUCH: Column Fred not in Cursor
09-20 13:25:35.164 4217-4217/? D/NOTĀ OUCH: Column aislename is in Cursor
I wouldn't mind the repetition if we could extract that code into a
separate method to be called for each column. But I don't see any
simple way to do it, because the columns can have different types. (We
could subclass CursorWrapper and implement getInt(), getString(), etc.
to do the checking we want, thus confining the repetition to a
specialized utility class. Is that the best we can do?)
I'm not really sure if the above code (isColumnInCursor method) would suit your requirements although I'm pretty sure it meets the single seperate method, at least for detecting the missing column condition.
Any other ideas? Any thoughts on the above ideas?
The above!?
I'm having some difficulty getting my database updated. Basically the user will input data into two separate places, so we get
Name | Letter | Marks
----------------------------
Dave | Null | 90
Dave | A | Null
which should become
Dave | A | 90
However, nothing is updating. The query works perfectly when I try it in SQLite Manager, so I must be implementing cursor wrong.
public void insertData(String name, int mark_column, String marks) {
String [] columns = new String[] {COL_3, COL_4, COL_5};
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL_2, name);
contentValues.put(columns[mark_column], marks);
db.replace(TABLE_NAME, null, contentValues);
//The code above works as desired
String sql = "SELECT NAME, GROUP_CONCAT(LETTER, ', ') AS LETTER," +
"GROUP_CONCAT(MARKS, ', ') AS MARKS FROM " + TABLE_NAME + " GROUP BY NAME";
//This query works in SQLite Manager
Cursor c = db.rawQuery(sql, null);
c.moveToFirst();
while(c.moveToNext());
c.close();
}
I have tried various combinations of c.moveToLast, not having c.moveToNext, etc. This method is called in onClick of an Alert Dialog.
Any help is greatly appreciated
Regarding the cursor:
I don't see anything wrong with your query. If you aren't "seeing" any results in your app, it's likely because you aren't actually doing anything with the results. They exist in memory in a Cursor object, but that's all; if you want to see anything you have to bind that data to some UI components, or dump it to logcat, or something.
Note that if you were to add code inside of your while loop, you would skip the first row of the cursor because you would have a moveToFirst() call followed immediately by a moveToNext() call. This is how I iterate over a Cursor, and it always works:
if (cusor != null) {
try {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
// do something with data in current row
}
} finally {
cursor.close();
}
}
Regarding the update:
You actually aren't doing an update per se, you are doing an insert. SQLiteDatabase.replace() executes this command:
INSERT OR REPLACE INTO tableName(columns) VALUES (values);
This can work as an update only if you have a constraint on the table and the insertion of a new row with these values would violate that constraint (the exact handling for different constraint violations is described here). For the constraint types that I suspect you are expecting, this operation will delete the existing row and insert a new row with these values, but it will not carry over values from the deleted row into the new one. In other words, you need all the combined values in the ContentValues if you expect a replace to occur. It's not like an UPDATE where you can set the values of just certain columns.
You should probably try to do an actual update instead. Make sure to use a proper WHERE clause so you only update rows that matter.
I may be misunderstanding your approach, but the description makes it seem like you are inserting two rows, then trying to update and/or combine them both later. This doesn't make sense to me, and I foresee bugs whereby you have leftover rows that are incomplete and need to be cleaned up. In my opinion, it's better to structure the code so there is one INSERT, and every operation thereafter is an UPDATE on the row of interest.
In android, SQLiteDatabase has a update function
update(String table, ContentValues values, String whereClause, String[] whereArgs)
new values in put in values
If I want to update a column A by adding one to it, how should I prepare the ContentValues values variable? I don't think the following would work.
cv.put("A", "A" + 1);
I can sure run execSQL with raw sql, but it does not return num of row updated
If you'd execute a raw query, something like this should work to increment the current value in the column:
UPDATE table_name SET column_a = column_a + 1 WHERE _id = 1
(where 1 is just an example to illustrate how to apply it to a specific row)
The same probably wouldn't work with ContentValues, since (as the name indicates) it takes the values to set the column to. That means it needs to have been evaluated before building the ContentValues, whereas with a raw query the value isn't evaluated until the query actually runs on the database.
You can of course retrieve the current value first and then increment that accordingly when issuing an update; that requires a select query first. Quite commonly though, you're working with objects in Java, where the column value for a row is bound up to a member field of the object. If you've got a setup like that, then you probably already have the current value at the moment you want to run an update query.
As such, it would just look somewhat like:
SomeObject object = ...;
cv.put("column_a", object.getSomeValue() + 1);
(where I'm assuming object.getSomeValue() will return an int)
// edit: here's some more examples for the raw query approach:
SQLite - increase value by a certain number
// edit2: You've edited your original question and added:
I can sure run execSQL with raw sql, but it does not return num of
row updated
If knowing how many rows the query changed is a must, then you can potentially leverage the changes() function. It still means you're going to have to run a second query though.
SELECT changes() FROM table_name
The docs say:
The changes() function returns the number of database rows that were
changed or inserted or deleted by the most recently completed INSERT,
DELETE, or UPDATE statement, exclusive of statements in lower-level
triggers. The changes() SQL function is a wrapper around the
sqlite3_changes() C/C++ function and hence follows the same rules for
counting changes.
Alternatively, you could look into the rawQuery() method that takes an SQL statement and returns the result as a Cursor. Not sure if it that even works for an update query, or whether the result would be anything sensible, but if you're really lucky, you may find that Cursor.getCount() gives you the number of affected rows.
To expand upon #MH's solution, there actually is a way to do a raw update AND get back the number of rows updated (because I'm doing the same thing in one of my projects). You have to use a compiled SQLiteStatement and then call the method executeUpdateDelete(). From the documentation:
public int executeUpdateDelete ()
Execute this SQL statement, if the the number of rows affected by execution of this SQL statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
Returns
the number of rows affected by this SQL statement execution.
See the following sample code where I add a new column to my table and then update each column similarly to how you were asking:
db.beginTransaction();
try {
db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN "
+ COLUMN_NAME_LOCALTIME + " INTEGER");
String stmtString = "UPDATE " + TABLE_NAME + " SET "
+ COLUMN_NAME_LOCALTIME + "="
+ COLUMN_NAME_TIME + "+ (" + tzOffset + ")";
SQLiteStatement sqlStmt = db.compileStatement(stmtString);
int rows = sqlStmt.executeUpdateDelete();
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
I'm using a transaction here because in case I add the new column but CANNOT update the values, I want everything to rollback so I can attempt something else.
I have a database with 4 columns. Everything works fine except for the fact that random rows remain inaccessible. I cannot seem to update or delete them. I've used the right code:
DELETION CODE:
boolean deleted=db.delete(TABLE_NAME, KEY_BLAH + "=" + alarm, null) > 0;
CODE FOR UPDATE:
db.update(TABLE_NAME, args, KEY_BLAH + "=" + blah, null)
The deletion code returns false and the update code returns 0 for some rows, which are arbitrary. The rows are implemented into a ListView. Any changes on the ListView elements should be reflected in the SQLite Database. Most of the times the code works. It doesn't seem to work for random rows at random points though. I do not think this is SDK related. I've tried it on ICS, GB and JB.
I've also tried deleting the row and inserting it. Obviously this wouldn't work because my delete statement doesn't seem to work. The logic for this was, if the update wasn't possible it would delete the row and insert the row with the same row id and different data. So, the deleted variable was the condition for an if-block which didn't get executed.
EDIT
Example:
1 1414 000 off
When I click on a few buttons in the list item.
It should become
1 1414 064 off
Now, this works most of the times except for some random rows as I said before.
If you (indirectly) execute an SQL statement like this:
UPDATE MyTable SET x = '064' WHERE blah = 1414
then the values in the blah column are compared with the number 1414.
When using strings in SQL statements, you should always use parameters to avoid formatting problems like this (and SQL injection attacks):
db.update(TABLE_NAME, args, KEY_BLAH + "= ?", new String[] { blah })
I think it's kinda easy one but still I'm new to android programming so please have patience. I want to know how can I get the number of records (rows) in a specific table in my db. I need this so I can create a loop to go through every record and add each one of it to the specific Array and display it later on. This is the source:
db.openDataBase(); // open connection with db
Cursor c = db.getTitle(5); // loop here through db, right now I'm fetching only one record
startManagingCursor(c);
//adding areas to the list here
Area o1 = new Area();
o1.setOrderName(c.getString(1) + c.getString(2));
m_areas.add(o1);
db.close();
Does anyone can help me with this please? Thx in advance!
SELECT COUNT(*) FROM tablename
To get the number of rows in the cursor, use getCount.
To get the amount of total rows in a table, either use reinierposts solution, or do a select which select all rows in the table and get the count from the cursor. I'm guessing his solution is quicker though unless you actually need all the rows in the table.
Such a query would be:
SELECT * FROM footable;
You don't really need to get a count of how many first; instead, create a db.getTitles() function that returns all of the rows and returns a Cursor, then loop over the Cursor. Right now you probably have a query that looks something like SELECT ColumnA, ColumnB FROM Titles WHERE id = 5; just copy the function, remove the parameter and take off the WHERE clause so it looks like just SELECT ColumnA, ColumnB FROM Titles.
Then your code would look something like this:
db.openDataBase(); // open connection with db
Cursor c = db.getTitles();
startManagingCursor(c);
//adding areas to the list here
if (c != null && c.moveToFirst()) {
do {
Area o1 = new Area();
o1.setOrderName(c.getString(1) + c.getString(2));
m_areas.add(o1);
} while (c.next());
}
db.close();
We check if the function returned a cursor at all, then move to the beginning of the cursor and start looping, going to the next item each time through. For more information on the Cursor interface see the API here, or to learn more about database access and related design practices better in general I suggest going through the Notepad tutorial.