Làm cách nào để sử dụng các câu lệnh đã soạn sẵn trong SQlite trong Android?


100

Làm cách nào để sử dụng các câu lệnh đã soạn sẵn trong SQlite trong Android?


9
Cân nhắc thay đổi câu trả lời được chấp nhận.
Suragch

9
đồng ý - xem xét thay đổi câu trả lời ... tâm lý bầy đàn ủng hộ câu trả lời được chấp nhận, khi một giải pháp tốt hơn tồn tại.
goodguys_activate

4
Pablo, vui lòng thay đổi câu trả lời được chấp nhận ... ví dụ được đưa ra thậm chí không chạy. Và số phiếu phản đối của chúng tôi không đủ để bỏ ghim nó.
SparK

Câu trả lời:


21

Tôi sử dụng các câu lệnh chuẩn bị sẵn trong Android mọi lúc, nó khá đơn giản:

SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("INSERT INTO Country (code) VALUES (?)");
stmt.bindString(1, "US");
stmt.executeInsert();

81
Tôi không biết làm thế nào mà câu trả lời này có thể có nhiều phiếu bầu như vậy. SQLIteStatement # thực thi không nên được sử dụng cho các truy vấn Sql, chỉ các câu lệnh. Vui lòng kiểm tra developer.android.com/reference/android/database/sqlite/…
simao

9
Sau đó, làm thế nào bạn phải sử dụng một câu lệnh đã chuẩn bị sẵn để truy vấn dữ liệu?
Juan Mendes

12
Lưu ý rằng SQLiteStatement.bindXXX()có chỉ mục dựa trên 1, không dựa trên 0 như hầu hết các chỉ số.
Simulant

6
@jasonhudgins Tại sao không thay thế CHỌN của bạn bằng CHÈN? Tôi chỉ đến từ chủ đề này , nơi bạn đã nhầm lẫn với người mới bắt đầu
keyer

35
ví dụ hoàn hảo của tâm lý bầy đàn mà upvotes và chấp nhận một câu trả lời đó là hoàn toàn không chính xác

165

Đối với các câu lệnh SQLite đã chuẩn bị sẵn trong Android, có SQLiteStatement . Các câu lệnh chuẩn bị sẵn giúp bạn tăng tốc hiệu suất (đặc biệt đối với các câu lệnh cần được thực thi nhiều lần) và cũng giúp tránh các cuộc tấn công chèn ép. Xem bài viết này để thảo luận chung về các tuyên bố đã chuẩn bị.

SQLiteStatementđược sử dụng với các câu lệnh SQL không trả về nhiều giá trị. (Điều đó có nghĩa là bạn sẽ không sử dụng chúng cho hầu hết các truy vấn.) Dưới đây là một số ví dụ:

Tạo bảng

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

Các execute()phương pháp không trả lại một giá trị nên rất thích hợp để sử dụng với CREATE và thả nhưng không nhằm phản ánh được sử dụng với SELECT, INSERT, DELETE, và UPDATE bởi vì những giá trị trả về. (Nhưng hãy xem câu hỏi này .)

Chèn giá trị

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

Lưu ý rằng executeInsert()phương pháp được sử dụng hơn là execute(). Tất nhiên, bạn sẽ không muốn luôn nhập những thứ giống nhau ở mọi hàng. Đối với điều đó, bạn có thể sử dụng các ràng buộc .

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

Thông thường, bạn sử dụng các câu lệnh chuẩn bị sẵn khi bạn muốn lặp lại nhanh một điều gì đó (như CHÈN) nhiều lần. Câu lệnh đã chuẩn bị sẵn giúp cho câu lệnh SQL không phải được phân tích cú pháp và biên dịch mọi lúc. Bạn có thể tăng tốc mọi thứ hơn nữa bằng cách sử dụng các giao dịch . Điều này cho phép tất cả các thay đổi được áp dụng cùng một lúc. Đây là một ví dụ:

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

Kiểm tra các liên kết này để biết thêm một số thông tin tốt về giao dịch và tăng tốc độ chèn cơ sở dữ liệu.

Cập nhật hàng

Đây là một ví dụ cơ bản. Bạn cũng có thể áp dụng các khái niệm từ phần trên.

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

Xóa hàng

Các executeUpdateDelete()phương pháp cũng có thể được sử dụng cho lệnh DELETE và đã được giới thiệu trong API 11. Xem Q & A .

Đây là một ví dụ.

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

Truy vấn

Thông thường khi bạn chạy một truy vấn, bạn muốn lấy lại một con trỏ với nhiều hàng. Tuy nhiên, đó không phải SQLiteStatementlà những gì dành cho. Bạn không chạy truy vấn với nó trừ khi bạn chỉ cần một kết quả đơn giản, chẳng hạn như số hàng trong cơ sở dữ liệu, bạn có thể thực hiện vớisimpleQueryForLong()

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

Thông thường bạn sẽ chạy query()phương thức SQLiteDatabase để lấy con trỏ.

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

Xem câu trả lời này để biết chi tiết tốt hơn về các truy vấn.


5
Xin nhắc lại: các phương thức .bindString / .bindLong / ... đều dựa trên 1 phương thức.
Denys Vitali

Tôi đã tìm hiểu kỹ các phương pháp tiện lợi của Android như .query, .insert và .delete và nhận thấy rằng chúng sử dụng SQLiteStatement. Sẽ không dễ dàng hơn nếu chỉ sử dụng các phương pháp tiện lợi thay vì xây dựng các câu lệnh của riêng bạn?
Nicolás Carrasco

@ NicolásCarrasco, đã lâu rồi tôi không làm việc này nên bây giờ tôi hơi thất vọng. Đối với các truy vấn và chèn đơn, cập nhật và xóa, tôi chắc chắn sẽ sử dụng các phương pháp tiện lợi. Tuy nhiên, nếu bạn đang thực hiện việc chèn, cập nhật hoặc xóa hàng loạt, tôi sẽ xem xét các bản sao kê đã chuẩn bị cùng với một giao dịch. Về việc SQLiteStatement được sử dụng ẩn và liệu các phương pháp tiện lợi có đủ tốt hay không, tôi không thể nói về điều đó. Tôi đoán tôi sẽ nói, nếu các phương pháp tiện lợi hoạt động đủ nhanh cho bạn, thì hãy sử dụng chúng.
Suragch

Tại sao bạn sử dụng clearBindings ()? Bạn ràng buộc tất cả các giá trị của mình mà không có bất kỳ điều kiện nào. Đối với tôi, không có ý nghĩa gì khi đặt chúng là null trước và giá trị thực.
Điều đáng kinh ngạc

@TheincredibleJan, tôi không biết chắc. Nó có thể không cần thiết và bạn có thể thử nó mà không cần xóa các ràng buộc để xem nó có tạo ra sự khác biệt hay không. Tuy nhiên, điều đó nói rằng, việc gọi clearBindings()không chỉ đặt chúng thành null(xem mã nguồn ). Tôi xem nó như là xóa trạng thái để không có gì ảnh hưởng đến nó từ vòng lặp trước. Có lẽ điều đó không cần thiết. Tôi rất vui vì ai đó biết nhận xét.
Suragch 9:18

22

Nếu bạn muốn con trỏ quay trở lại, thì bạn có thể xem xét điều gì đó như sau:

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

Xem đoạn mã này Genscripts trong trường hợp bạn muốn một đoạn hoàn chỉnh hơn. Lưu ý rằng đây là một truy vấn SQL được tham số hóa, vì vậy về bản chất, nó là một câu lệnh được chuẩn bị sẵn.


Lỗi nhỏ trong đoạn mã trên: Nó phải là "new String [] {strCountryCode}," thay vì "new String {strCountryCode}".
Pierre-Luc Simard

Bạn cần phải di chuyển con trỏ trước khi có thể truy xuất dữ liệu
Chin

9

ví dụ jasonhudgins sẽ không hoạt động. Bạn không thể thực hiện truy vấn với stmt.execute()và lấy lại giá trị (hoặc a Cursor).

Bạn chỉ có thể biên dịch trước các câu lệnh trả về không có hàng nào (chẳng hạn như câu lệnh chèn hoặc tạo bảng) hoặc một hàng và cột duy nhất, (và sử dụng simpleQueryForLong()hoặc simpleQueryForString()).


1

Để có được một con trỏ, bạn không thể sử dụng một Câu lệnh đã biên dịch. Tuy nhiên, nếu bạn muốn sử dụng một câu lệnh SQL đã chuẩn bị đầy đủ, tôi khuyên bạn nên chuyển thể phương pháp của jbaez ... Sử dụng db.rawQuery()thay vì db.query().

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.