¿Cómo uso declaraciones preparadas en SQlite en Android?

Resuelto Pablo Fernandez asked hace 54 años • 5 respuestas

¿Cómo uso declaraciones preparadas en SQlite en Android?

Pablo Fernandez avatar Jan 01 '70 08:01 Pablo Fernandez
Aceptado

Para declaraciones SQLite preparadas en Android existe SQLiteStatement . Las declaraciones preparadas le ayudan a acelerar el rendimiento (especialmente para declaraciones que deben ejecutarse varias veces) y también ayudan a evitar ataques de inyección. Consulte este artículo para obtener una discusión general sobre declaraciones preparadas.

SQLiteStatementestá destinado a usarse con declaraciones SQL que no devuelven múltiples valores. (Eso significa que no los usaría para la mayoría de las consultas). A continuación se muestran algunos ejemplos:

Crear una tabla

String sql = "CREATE TABLE table_name (column_1 INTEGER PRIMARY KEY, column_2 TEXT)";
SQLiteStatement stmt = db.compileStatement(sql);
stmt.execute();

El execute()método no devuelve un valor, por lo que es apropiado usarlo con CREATE y DROP, pero no está diseñado para usarse con SELECT, INSERT, DELETE y UPDATE porque estos devuelven valores. (Pero vea esta pregunta ).

Insertar valores

String sql = "INSERT INTO table_name (column_1, column_2) VALUES (57, 'hello')";
SQLiteStatement statement = db.compileStatement(sql);
long rowId = statement.executeInsert();

Tenga en cuenta que executeInsert()se utiliza el método en lugar de execute(). Por supuesto, no querrás ingresar siempre lo mismo en cada fila. Para eso puedes usar fijaciones .

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();

Por lo general, utiliza declaraciones preparadas cuando desea repetir algo rápidamente (como un INSERT) muchas veces. La declaración preparada hace que la declaración SQL no tenga que ser analizada y compilada cada vez. Puede acelerar aún más las cosas mediante el uso de transacciones . Esto permite que todos los cambios se apliquen a la vez. Aquí hay un ejemplo:

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();
}

Consulte estos enlaces para obtener más información útil sobre transacciones y cómo acelerar las inserciones en bases de datos.

  • Compromiso atómico en SQLite (Excelente explicación detallada, vaya a la Parte 3)
  • Transacciones de base de datos
  • Ejemplo de inserción y actualización masiva de Android SQLite
  • Ejemplo de transacción SQLite de Android con declaración preparada INSERT
  • Acelere sus inserciones SQLite en Android
  • https://stackoverflow.com/a/8163179/3681880

Actualizar filas

Este es un ejemplo básico. También puede aplicar los conceptos de la sección anterior.

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();

Eliminar filas

El executeUpdateDelete()método también se puede utilizar para declaraciones DELETE y se introdujo en API 11. Consulte estas preguntas y respuestas .

Aquí hay un ejemplo.

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();
}

Consulta

Normalmente, cuando ejecuta una consulta, desea recuperar un cursor con muchas filas. Aunque no SQLiteStatementes para eso. No ejecuta una consulta con él a menos que solo necesite un resultado simple, como el número de filas en la base de datos, lo cual puede hacer consimpleQueryForLong()

String sql = "SELECT COUNT(*) FROM table_name";
SQLiteStatement statement = db.compileStatement(sql);
long result = statement.simpleQueryForLong();

Normalmente ejecutará el query()método de SQLiteDatabase para obtener un 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);

Consulte esta respuesta para obtener mejores detalles sobre las consultas.

Suragch avatar Apr 22 '2015 12:04 Suragch

Utilizo declaraciones preparadas en Android todo el tiempo, es bastante simple:

SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("INSERT INTO Country (code) VALUES (?)");
stmt.bindString(1, "US");
stmt.executeInsert();
jasonhudgins avatar Jan 12 '2009 17:01 jasonhudgins

Si desea un cursor al regresar, entonces podría considerar algo como esto:

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"));

Vea este fragmento de Genscripts por si desea uno más completo. Tenga en cuenta que se trata de una consulta SQL parametrizada, por lo que, en esencia, es una declaración preparada.

jbaez avatar Sep 03 '2010 14:09 jbaez

El ejemplo de Jasonhudgins no funcionará. No puede ejecutar una consulta stmt.execute()y recuperar un valor (o un Cursor).

Solo puede precompilar declaraciones que no devuelvan ninguna fila (como una instrucción de inserción o creación de tabla) o una sola fila y columna (y use simpleQueryForLong()o simpleQueryForString()).

redfish64 avatar Jun 06 '2010 09:06 redfish64

Para obtener un cursor, no puede utilizar una declaración compilada. Sin embargo, si desea utilizar una declaración SQL completamente preparada, le recomiendo una adaptación del método de jbaez... Usar db.rawQuery()en lugar de db.query().

Aaron avatar Oct 14 '2010 18:10 Aaron