How do I use prepared statements in SQlite in Android?

pupeno picture pupeno · Jan 11, 2009 · Viewed 91k times · Source

How do I use prepared statements in SQlite in Android?

Answer

Suragch picture Suragch · Apr 22, 2015

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.

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.