2009-01-11 6 views
82

Wie verwende ich vorbereitete Anweisungen in SQlite in Android?Wie verwende ich vorbereitete Anweisungen in SQlite in Android?

+7

Überlegen Sie, die akzeptierte Antwort zu ändern. – Suragch

+8

einverstanden - erwägen, die Antwort zu ändern ... Herdenmentalität hat die akzeptierte Antwort aufgewertet, wenn eine bessere Lösung existiert. – LamonteCristo

+3

Pablo, bitte ändere die angenommene Antwort ... das angegebene Beispiel läuft nicht einmal. Und unsere Downvotes sind nicht genug, um es zu lösen. – SparK

Antwort

30

ich vorbereitete Anweisungen in Android die ganze Zeit, es ist ganz einfach:

SQLiteDatabase db = dbHelper.getWritableDatabase(); 
SQLiteStatement stmt = db.compileStatement("SELECT * FROM Country WHERE code = ?"); 
stmt.bindString(1, "US"); 
stmt.execute(); 
+0

Ist es mit vorbereiteten Aussagen möglich, Argumente zu setzen, die keine Werte sind? wie "SELECT * FROM?"? – Pablo

+70

Ich weiß nicht, wie diese Antwort so viele Stimmen haben kann. SQLIteStatement # execute sollte nicht für SQL-Abfragen, nur für Anweisungen verwendet werden. Bitte überprüfen Sie http://developer.android.com/reference/android/database/sqlite/SQLiteStatement.html#execute() – simao

+1

Ja, das ist ein schlechtes Beispiel, das ich gab, es funktioniert nicht für Abfragen wie SELECT-Anweisungen ... – jasonhudgins

9

jasonhudgins Beispiel wird nicht funktionieren. Sie können keine Abfrage mit stmt.execute() ausführen und erhalten einen Wert (oder Cursor) zurück.

Sie können nur precompile Aussagen, die entweder zurückkehrt überhaupt keine Zeilen (wie ein Insert, oder create table-Anweisung) oder eine einzelne Zeile und Spalte (und verwenden simpleQueryForLong() oder simpleQueryForString()).

22

Wenn Sie einen Cursor auf Rückkehr wollen, dann könnten Sie so etwas wie dies berücksichtigen:

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

Sehen Sie diese Schnipsel Genscripts falls Sie eine vollständigere ein. Beachten Sie, dass dies eine parametrisierte SQL-Abfrage ist, also im Wesentlichen eine vorbereitete Anweisung.

+0

Kleiner Fehler im obigen Code: Es sollte "new String [] {strCountryCode}, "anstelle von" new String {strCountryCode} ". –

+0

Sie müssen den Cursor bewegen, bevor Sie die Daten abrufen können – Chin

1

Um einen Cursor zu erhalten, können Sie kein compiledStatement verwenden. Wenn Sie jedoch eine vollständig vorbereitete SQL-Anweisung verwenden möchten, empfehle ich eine Anpassung der jbaez-Methode ... Unter Verwendung von db.rawQuery() anstelle von db.query().

131

Für vorbereitete SQLite-Anweisungen in Android gibt es SQLiteStatement. Vorbereitete Anweisungen helfen Ihnen dabei, die Leistung zu beschleunigen (insbesondere bei Anweisungen, die mehrfach ausgeführt werden müssen) und vermeiden außerdem Angriffe gegen Injektionen. Eine allgemeine Diskussion über vorbereitete Aussagen finden Sie unter this article.

SQLiteStatement ist für die Verwendung mit SQL-Anweisungen gedacht, die nicht mehrere Werte zurückgeben. (Das bedeutet, dass Sie nicht sie für die meisten Abfragen verwenden würde.) Im Folgenden sind einige Beispiele:

Create a table

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

Die execute() Methode einen Wert nicht zurück, so dass es angemessen ist, die mit CREATE und DROP zu verwenden, aber aufgrund dieser Rückgabewerte nicht mit SELECT, INSERT, DELETE und UPDATE verwendet werden soll. (Aber siehe 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(); 

Beachten Sie, dass die executeInsert() Methode anstatt execute() verwendet wird. Natürlich möchten Sie nicht immer die gleichen Dinge in jeder Zeile eingeben. Dafür können Sie bindings verwenden.

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); // These match to the two question marks in the sql string 
statement.bindString(2, stringValue); 

long rowId = statement.executeInsert(); 

Normalerweise verwenden Sie vorbereitete Anweisungen, wenn Sie schnell etwas wiederholen möchten (wie ein INSERT). Die vorbereitete Anweisung macht es so, dass die SQL-Anweisung nicht jedes Mal analysiert und kompiliert werden muss. Sie können die Dinge sogar noch beschleunigen, indem Sie transactions verwenden. Dadurch können alle Änderungen gleichzeitig angewendet werden. Hier ist ein Beispiel:

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

Überprüfen Sie diese Links für einige weitere gute Informationen über Transaktionen und Beschleunigung von Datenbankeinfügungen.

Update rows

Dies ist ein einfaches Beispiel. Sie können auch die Konzepte aus dem obigen Abschnitt anwenden.

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

Hinweis: executeUpdateDelete() kann auch für DELETE-Anweisungen verwendet werden und wurde in API 11. See this Q&A eingeführt.

Query

Normalerweise, wenn Sie eine Abfrage ausführen, möchten Sie einen Cursor zurück mit vielen Zeilen erhalten. Das ist nicht, was SQLiteStatement ist, obwohl. Sie haben nicht eine Abfrage mit ihm ausgeführt werden, wenn Sie nur ein einfaches Ergebnis benötigen, wie die Anzahl der Zeilen in der Datenbank, die Sie mit simpleQueryForLong()

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

tun können Normalerweise laufen Sie query() Methode von SQLiteDatabase zu erhalten ein Cursor.

Weitere Details zu Abfragen finden Sie unter this answer.

+1

Nur zur Erinnerung: die .bindString/.bindLong/... Methoden sind alle 1-basiert. –

+0

Erstaunliche Antwort! Danke @Suragh –

+0

Ich suchte unter der Haube von Android-Komfort-Methoden wie .query, .insert und .delete und bemerkte, dass sie SQLiteStatement unter der Haube verwenden. Wäre es nicht einfacher, nur Convenience-Methoden zu verwenden, anstatt eigene Aussagen zu erstellen? –

Verwandte Themen