2014-10-07 2 views
1

Как удалить несколько строк по списку идентификаторов в базе данных Android SQLite?Удалить несколько строк с помощью идентификаторов?

Я определил общий метод удаления таким образом:

protected void deleteWhere(String whereClause, String[] whereArgs) { 
    try { 
     databaseHelper.getWritableDatabase().delete(
       getTableName(), whereClause, whereArgs); 
    } finally { 
     databaseHelper.close(); 
    } 
} 

И теперь я пытаюсь вызвать его со списком идентификаторов:

public void deleteAll(Iterable<T> entities) { 
    Iterable<Long> ids = Iterables.transform(entities, getId); 

    String whereClause = getIdColumn() + " IN (?)"; 
    String[] whereArgs = { TextUtils.join(",", ids) }; 
    deleteWhere(whereClause, whereArgs); 
} 

Если список ID содержит для пример значения [1, 2, 42], то я предполагаю, что полученный SQL должен быть:

DELETE FROM tableName WHERE _id IN (1,2,42); 

Но это не похоже на работу сотрудничества rrectly. Если список содержит только 1 идентификатор, он будет удален. Однако, если я предоставляю несколько значений, это влияет на нулевые строки. Что я делаю не так?

ответ

3

Когда вы даете одну строку, в качестве whereArgs, одна строка заканчивается в команде SQL, как если бы вы написали:

... WHERE _id IN ('1,2,42') 

Это сравнило бы значение _id со значением '1,2,42', что, конечно же, не работает.

Если вы используете три маркеры параметров и дать три строки в whereArgs массиве, вы бы в конечном итоге с тремя строками, например:

... WHERE _id in ('1','2','42') 

Это работает только тогда, когда _id столбец имеет целочисленное affinity, который true для столбца, объявленного как INTEGER PRIMARY KEY, но не в общем случае.

API базы данных Android не позволяет параметрам запроса иметь любой тип, кроме строки. При использовании целых чисел, нужно просто вставить их непосредственно (как в ianhanniballake's answer):

String whereClause = getIdColumn() + " IN (" + TextUtils.join(",", ids) + ")"; 
+0

О, теперь, когда я вижу способ добавления апострофов к значениям, это имеет смысл. Однако, не помещает ли значения непосредственно в 'whereClause', склонный к SQL-инъекции? Не лучше ли вручную генерировать 'whereClause' с соответствующим количеством вопросительных знаков, а затем передавать идентификаторы в массив' whereArgs' как String? – Natix

+0

Разрешение только строк как параметров является ошибкой в ​​дизайне API баз данных Android. В любом случае, целочисленные значения безопасны для SQL-инъекций; эта проблема возникает только со строками. –

0

Каждый "?" будет привязываться только к одному значению. Так что если ваш список идентификаторов имеет три значения, ваш WhereClause должны были бы быть «_id IN (?,?,?)»

+0

Но я передаю идентификаторы в одну строку, состоящую из значений, соединенных запятыми. Это не разрешено? – Natix

+0

Хорошая точка - ваш whereArgs также должен быть массивом из трех значений, а не одной разделенной запятой строкой. – eshayne

2

Вы не можете использовать whereArgs для IN заявлений в связи с отводящей сделано whereArgs (если вы сделаете отдельный ? для каждого значения) - вместо этого, вы должны вставлять идентификаторы в вашем где высказыванием:

String whereClause = getIdColumn() + " IN (" + TextUtils.join(",", ids) + ")"; 
deleteWhere(whereClause, null);