I tried the following SQLite query:
int idServizo = 150;
String whereClause = id_servizio+" = '"+idServizio+" ' ";
ContentValues cv = new ContentValues();
cv.put("sync", 1);
int r = dbManager.updateTable("myTable", cv, whereClause);
Where fields sync and id_servizio are both integer.
The method updateTable is:
public int updateTable(String table, ContentValues values, String whereClause){
int r = mDb.update(table, values, whereClause, null);
return r;
}
// mDb is SQLiteDatabase object
All this works good.
But if I try this with the rawQuery() method:
public Cursor RawQuery(String sqlQuery, String[] columns){
return mDb.rawQuery(sqlQuery, columns);
}
The table is not updated! even if no error occurs.
int idServizo = 150;
String updateQuery ="UPDATE myTable SET sync = 1 WHERE id_servizio = "+idServizio;
dbManager.RawQuery(updateQuery, null);
Why does this not work?
This is because when a rawQuery is executed cursor is returned. Without the call to cursor.moveToFirst() and cursor.close() the database won't get updated.
int idServizo = 150;
String updateQuery ="UPDATE myTable SET sync = 1 WHERE id_servizio = "+idServizio;
Cursor c= dbManager.rawQuery(updateQuery, null);
c.moveToFirst();
c.close();
I dont know the need to call moveToFirst() but this works fine and the database gets updated.
Problem solved.
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
Can't works because rawQuery runs the provided SQL and returns a Cursor over the result set.
If I want to return a table I have to use rawQuery, otherwise no!
Increase the value of a record in android/sqlite database
You should use db.execSQL() instead db.rawQuery().
Instead of doing this:
Cursor c= dbManager.RawQuery(updateQuery, null);
c.moveToFirst();
c.close();
You just need this:
dbManager.execSQL(updateQuery, null);
----------------------------------------------------------------------------
Posting answer because sometimes many people (like me) not reading comments.
Most popular answer is not correct but Yaqub Ahmad's comment is correct.
Answer from CommonsWare explained in this answer:
rawQuery() is for SQL statements that return a result set. Use
execSQL() for SQL statements, like INSERT, that do not return a result
set.
----------------------------------------------------------------------------
Documentation for execSQL:
public void execSQL (String sql)
Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
Documentation for rawQuery:
public Cursor rawQuery (String sql,
String[] selectionArgs)
Runs the provided SQL and returns a Cursor over the result set.
Your update call formats the ID as string, while the rawQuery call formats is as number.
Assuming that the ID in the table indeed is a string, use:
String updateQuery = "UPDATE myTable SET sync = 1 WHERE id_servizio = '" + idServizio + "'";
Related
I am getting an error with the method below.
I would like to do a SELECT WHERE statement.
My goal is to know, if the variable name is already in my database.
The error seems to occur at statement.execute(); It is :-
"Caused By : unknown error (code 0): Queries can be performed using SQLiteDatabase query or rawQuery methods only. "
The program has worked properly many times before but now it does not.
The method is :-
public int count(String name) {
SQLiteDatabase database = getWritableDatabase();
String countQuery = "SELECT * FROM myBD WHERE NAME1 = ?";
SQLiteStatement statement = database.compileStatement(countQuery);
statement.clearBindings();
statement.bindString(1, name);
statement.execute();
//database.close();
SQLiteDatabase db = this.getReadableDatabase();enter code here
Cursor cursor = db.rawQuery(countQuery, null);
int count = cursor.getCount();
cursor.close();
database.close();
return count;
}
You could use the query convenience method e.g. :-
public int count(String name) {
SQLiteDatabase database = getWritableDatabase();
String whereclause = "NAME1=?";
String[] whereargs = new String[]{name};
Cursor cursor = database.query("myBD",null,whereclause,whereargs,null,null,null);
int count = cursor.getCount();
cursor.close();
database.close();
return count;
}
Note the above is in-principle code, it hasn't been checked or run and may therefore contain some errors.
Unknown errors are often related to subsequent lines following a ; the convenience methods enclose arguments and build the SQL on your behalf.
You can also use
database.rawQuery("Your query here");
I am developing an application where the user inputs title and the date. I want to prevent the duplicated titles being inputted on the same day in to database. I am checking if the title exists on the selected date. However my query seems not to work and i don't know why, the application just crashes.Is this query correct? Can someone help?
public boolean checkExist(String title, String date) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
boolean exists = c.moveToFirst();
c.close();
return exists;
}
One issue that you have is that c.moveToFirst will always fail if a match does not exist as you are trying to move to a row in an empty cursor.
The resolution is to not use c.moveToFirst and instead get the count of the rows and then set the return value accordingly.
e.g.
public boolean checkExist(String title, String date) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
boolean exists = c.getCount() > 0;
c.close();
return exists;
}
The second issue is that the query itself is wrong as you do not have spaces either side of the AND keyword. That is instead of
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +"AND" + DATE+"=?", new String[] {title,date});
You should have
Cursor c = db.rawQuery("SELECT * FROM "+TABLE_NAME+" WHERE "+TITLE+"=?" +" AND " + DATE+"=?", new String[] {title,date});
Personally, I setup constants for SQL keywords that include the space and then use these. So I'd have something along the lines of +TITLE+"=?" + SQLAND + DATE+"=?". Where SQLAND would be defined along the lines of String SQLAND=" AND ";
PS look at Cricket_007's answer, the code is neater/better it's easier to read.
Your spacing is off. TITLE+"=?" +"AND" + DATE becomes TITLE=?ANDDATE=?
I would suggest this. See DatabaseUtils.queryNumEntries
public boolean checkExist(String title, String date) {
SQLiteDatabase db = getReadableDatabase();
String[] args = new String[] {title,date};
String filter = String.format("%s=? AND %s=?", TITLE, DATE);
return DatabaseUtils.queryNumEntries(db, TABLE_NAME, filter, args) > 0;
}
you should be using c.getCount() instead of c.moveToFirst()
if the value is greater than 0, then it exists
I'm trying to get database row by it's ID, but somehow query doesn't return that row. The sql query SELECT * From Table1 Where _id = 100 works good, so I don't know what's the reason. Here is the code of the query:
String [] selectedArgs = new String [] {String.valueOf(selectedItemId)};
String selection = Tables.Table1.COLUMN_ID + "=?";
String [] columns = {Tables.Table1.COLUMN_ID, Tables.Table1.COLUMN_NAME};
Cursor c = foodDB.query(Tables.Food.TABLE_NAME, columns, selection, selectedArgs, null, null, null);
Does anybody have any suggestions?
The problem is that your ID field is a number, while the parameter is a string; the query function does not allow other parameter types for some strange reason.
Try using an expression like COLUMN_ID + " = CAST(? AS INTEGER)".
If your query had only one result column, you could use a separate SQLiteStatement object where you'd be able to use bindLong().
Just in case somebody need it, i have used rawQuery() method for such type of query to work, because query() doesn't work.
I am trying to create a method to retrieve the max id of a specific table.
This is the code that doesn't work:
private long getMaxId()
{
String query = "SELECT MAX(id) AS max_id FROM mytable";
Cursor cursor = db.rawQuery(query, new String[] {"max_id"});
int id = 0;
if (cursor.moveToFirst())
{
do
{
id = cursor.getInt(0);
} while(cursor.moveToNext());
}
return id;
}
The exception being thrown is this:
E/AndroidRuntime(24624): android.database.sqlite.SQLiteException: bind or column index out of range: handle 0x200408
I suppose the problem is this line:
id = cursor.getInt(0);
Does anybody have an idea of how to fix this?
Thanks.
Try replacing:
Cursor cursor = db.rawQuery(query, new String[] {"max_id"});
with
Cursor cursor = db.rawQuery(query, null);
From the rawQuery description , for the 2nd argument:
You may include ?s in where clause in
the query, which will be replaced by
the values from selectionArgs. The
values will be bound as Strings.
Since you dont have any placeholders in your SQL query, maybe it is the source of the problem.
How do I use prepared statements in SQlite in Android?
For prepared SQLite statements in Android there is SQLiteStatement. Prepared statements help you speed up performance (especially for statements that need to be executed multiple times) and also help avoid against injection attacks. See this article for a general discussion on prepared statements.
SQLiteStatement is meant to be used with SQL statements that do not return multiple values. (That means you wouldn't use them for most queries.) Below are some examples:
Create a table
String sql = "CREATE TABLE table_name (column_1 INTEGER PRIMARY KEY, column_2 TEXT)";
SQLiteStatement stmt = db.compileStatement(sql);
stmt.execute();
The execute() method does not return a value so it is appropriate to use with CREATE and DROP but not intended to be used with SELECT, INSERT, DELETE, and UPDATE because these return values. (But see this question.)
Insert values
String sql = "INSERT INTO table_name (column_1, column_2) VALUES (57, 'hello')";
SQLiteStatement statement = db.compileStatement(sql);
long rowId = statement.executeInsert();
Note that the executeInsert() method is used rather than execute(). Of course, you wouldn't want to always enter the same things in every row. For that you can use bindings.
String sql = "INSERT INTO table_name (column_1, column_2) VALUES (?, ?)";
SQLiteStatement statement = db.compileStatement(sql);
int intValue = 57;
String stringValue = "hello";
statement.bindLong(1, intValue); // 1-based: matches first '?' in sql string
statement.bindString(2, stringValue); // matches second '?' in sql string
long rowId = statement.executeInsert();
Usually you use prepared statements when you want to quickly repeat something (like an INSERT) many times. The prepared statement makes it so that the SQL statement doesn't have to be parsed and compiled every time. You can speed things up even more by using transactions. This allows all the changes to be applied at once. Here is an example:
String stringValue = "hello";
try {
db.beginTransaction();
String sql = "INSERT INTO table_name (column_1, column_2) VALUES (?, ?)";
SQLiteStatement statement = db.compileStatement(sql);
for (int i = 0; i < 1000; i++) {
statement.clearBindings();
statement.bindLong(1, i);
statement.bindString(2, stringValue + i);
statement.executeInsert();
}
db.setTransactionSuccessful(); // This commits the transaction if there were no exceptions
} catch (Exception e) {
Log.w("Exception:", e);
} finally {
db.endTransaction();
}
Check out these links for some more good info on transactions and speeding up database inserts.
Atomic Commit In SQLite (Great in depth explanation, go to Part 3)
Database transactions
Android SQLite bulk insert and update example
Android SQLite Transaction Example with INSERT Prepared Statement
Turbocharge your SQLite inserts on Android
https://stackoverflow.com/a/8163179/3681880
Update rows
This is a basic example. You can also apply the concepts from the section above.
String sql = "UPDATE table_name SET column_2=? WHERE column_1=?";
SQLiteStatement statement = db.compileStatement(sql);
int id = 7;
String stringValue = "hi there";
statement.bindString(1, stringValue);
statement.bindLong(2, id);
int numberOfRowsAffected = statement.executeUpdateDelete();
Delete rows
The executeUpdateDelete() method can also be used for DELETE statements and was introduced in API 11. See this Q&A.
Here is an example.
try {
db.beginTransaction();
String sql = "DELETE FROM " + table_name +
" WHERE " + column_1 + " = ?";
SQLiteStatement statement = db.compileStatement(sql);
for (Long id : words) {
statement.clearBindings();
statement.bindLong(1, id);
statement.executeUpdateDelete();
}
db.setTransactionSuccessful();
} catch (SQLException e) {
Log.w("Exception:", e);
} finally {
db.endTransaction();
}
Query
Normally when you run a query, you want to get a cursor back with lots of rows. That's not what SQLiteStatement is for, though. You don't run a query with it unless you only need a simple result, like the number of rows in the database, which you can do with simpleQueryForLong()
String sql = "SELECT COUNT(*) FROM table_name";
SQLiteStatement statement = db.compileStatement(sql);
long result = statement.simpleQueryForLong();
Usually you will run the query() method of SQLiteDatabase to get a cursor.
SQLiteDatabase db = dbHelper.getReadableDatabase();
String table = "table_name";
String[] columnsToReturn = { "column_1", "column_2" };
String selection = "column_1 =?";
String[] selectionArgs = { someValue }; // matched to "?" in selection
Cursor dbCursor = db.query(table, columnsToReturn, selection, selectionArgs, null, null, null);
See this answer for better details about queries.
I use prepared statements in Android all the time, it's quite simple:
SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("INSERT INTO Country (code) VALUES (?)");
stmt.bindString(1, "US");
stmt.executeInsert();
If you want a cursor on return, then you might consider something like this:
SQLiteDatabase db = dbHelper.getWritableDatabase();
public Cursor fetchByCountryCode(String strCountryCode)
{
/**
* SELECT * FROM Country
* WHERE code = US
*/
return cursor = db.query(true,
"Country", /**< Table name. */
null, /**< All the fields that you want the
cursor to contain; null means all.*/
"code=?", /**< WHERE statement without the WHERE clause. */
new String[] { strCountryCode }, /**< Selection arguments. */
null, null, null, null);
}
/** Fill a cursor with the results. */
Cursor c = fetchByCountryCode("US");
/** Retrieve data from the fields. */
String strCountryCode = c.getString(cursor.getColumnIndex("code"));
/** Assuming that you have a field/column with the name "country_name" */
String strCountryName = c.getString(cursor.getColumnIndex("country_name"));
See this snippet Genscripts in case you want a more complete one. Note that this is a parameterized SQL query, so in essence, it's a prepared statement.
jasonhudgins example won't work. You can't execute a query with stmt.execute() and get a value (or a Cursor) back.
You can only precompile statements that either returns no rows at all (such as an insert, or create table statement) or a single row and column, (and use simpleQueryForLong() or simpleQueryForString()).
To get a cursor, you can't use a compiledStatement. However, if you want to use a full prepared SQL statement, I recommend an adaptation of jbaez's method... Using db.rawQuery() instead of db.query().