При использовании приведенного ниже кода я получаю следующую ошибку.
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);