Исключение SQLite с параметризованным запросом на удаление - PullRequest
0 голосов
/ 24 февраля 2012

При использовании приведенного ниже кода я получаю следующую ошибку.

02-24 12:13:16.972: E/AndroidRuntime(11024): Caused by: android.database.sqlite.SQLiteException: near "?": syntax error: , while compiling: DELETE FROM messages WHERE ? NOT IN ( SELECT ? FROM ? WHERE ?=? ORDER BY ? DESC LIMIT ?) AND ?=?
02-24 12:13:16.972: E/AndroidRuntime(11024):    at android.database.sqlite.SQLiteCompiledSql.native_compile(Native Method)
02-24 12:13:16.972: E/AndroidRuntime(11024):    at android.database.sqlite.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:92)
02-24 12:13:16.972: E/AndroidRuntime(11024):    at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:65)
02-24 12:13:16.972: E/AndroidRuntime(11024):    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:83)
02-24 12:13:16.972: E/AndroidRuntime(11024):    at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:41)
02-24 12:13:16.972: E/AndroidRuntime(11024):    at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1149)
02-24 12:13:16.972: E/AndroidRuntime(11024):    at android.database.sqlite.SQLiteDatabase.delete(SQLiteDatabase.java:1623)

Код:

// query idea from
// http://stackoverflow.com/questions/6528117/keep-only-n-last-records-in-sqlite-database-sorted-by-date
// I have added the AND ?=? because I only want to delete records from a particular conversation thread, not the entire table.
String whereClause = "? NOT IN ( SELECT ? FROM ? WHERE ?=? ORDER BY ? DESC LIMIT ?) AND ?=?";

String[] whereArgs = new String[]{
        DbAdapter.COL_ROWID,
        DbAdapter.COL_ROWID,
        DBConstants.DB_TABLE_MESSAGES,
        DbAdapter.COL_CONVERSATION_ID,
        String.valueOf(conversationId),
        DbAdapter.COL_TIMESTAMP,
        String.valueOf(numMessagesToRetain),
        DbAdapter.COL_CONVERSATION_ID,
        String.valueOf(conversationId)
};

deleted = mDb.delete(DBConstants.DB_TABLE_MESSAGES, whereClause,
        whereArgs);

Кроме того, документация по Android для метода удаления SQLite представляется неполной в отношении параметра whereArgs.

public int delete (String table, String whereClause, String[] whereArgs)

Since: API Level 1
Convenience method for deleting rows in the database.
Parameters

table   the table to delete from
whereClause the optional WHERE clause to apply when deleting. Passing null will delete all rows.
Returns

the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClause.

Это работает нормально, если я использую следующее условие where:

String whereClause = String
.format("%s NOT IN ( SELECT %s FROM %s WHERE %s=%s ORDER BY %s DESC LIMIT %s) AND %s=%s",
        DbAdapter.COL_ROWID,
        DbAdapter.COL_ROWID,
        DBConstants.DB_TABLE_MESSAGES,
        DbAdapter.COL_CONVERSATION_ID,
        String.valueOf(conversationId),
        DbAdapter.COL_TIMESTAMP,
        String.valueOf(numMessagesToRetain),
        DbAdapter.COL_CONVERSATION_ID,
        String.valueOf(conversationId));

Единственное, о чем я могу думать, это то, что метод delete не поддерживает параметризованные запросы, но работает следующий запрос, поэтому онисключает это.

mDb.delete(DB_TABLE_MESSAGES, COL_ROWID + "=?",
                new String[]{ String.valueOf(rowId)});

Решение

Благодаря antlersoft решение выглядит так:

String whereClause = String
        .format("(%s NOT IN ( SELECT %s FROM %s WHERE %s=? ORDER BY %s DESC LIMIT ?)) AND %s=?",
                DbAdapter.COL_ROWID,
                DbAdapter.COL_ROWID,
                DBConstants.DB_TABLE_MESSAGES,
                DbAdapter.COL_CONVERSATION_ID,
                DbAdapter.COL_TIMESTAMP,
                DbAdapter.COL_CONVERSATION_ID);

String[] whereArgs = new String[]{
        String.valueOf(conversationId),
        String.valueOf(numMessagesToRetain),
        String.valueOf(conversationId)
};

deleted = mDb.delete(DBConstants.DB_TABLE_MESSAGES, whereClause,
        whereArgs);

1 Ответ

1 голос
/ 24 февраля 2012

AFAIK, вы пытаетесь использовать параметризацию там, где это не разрешено.

Вы можете использовать параметризацию только для замены того, что в противном случае было бы постоянным значением в вашем запросе.

Вы также пытаетесь использовать его для замены идентификаторов, что не сработает.

Если вы хотите, чтобы идентификаторы были динамическими, замените их с помощью строковых манипуляций, прежде чем передавать запрос в SQLite; не передать их как? и ожидаем, что SQLite будет иметь смысл запроса ..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...