SQLiteDatabase.rawQuery не возвращает правильные результаты, используя подготовленный оператор

У меня есть странная и необъяснимая ошибка с моим подготовленным оператором SQL, он не дает тех же результатов, что и неподготовленный оператор.

Разве эти две версии не должны возвращать одинаковые результаты?

Подготовленная версия (с неправильными результатами):

sb.append(" WHERE c.deck_id=? AND c.next_date < ? AND c.next_date > 0 AND c.active > 0 AND c.deck_level=?");
...
return db.rawQuery(sb.toString(), new String[] { Long.toString(deckId)
, Long.toString(now), Long.toString(level)});

Неподготовленная версия (работает как положено с правильными результатами):

sb.append(" WHERE c.deck_id=").append(deckId)
.append(" AND c.next_date<").append(now)
.append(" AND c.next_date > 0 AND c.active > 0 AND c.deck_level=").append(level);
...
return db.rawQuery(sb.toString(), null);

Где ошибка в подготовленной версии выписки?

Обновление Я сделал дополнительные журналы для обеих версий.

Log.d(TAG, "selectionArgs1:" + Long.toString(deckId) + ""+Long.toString(now)+ ""+Long.toString(level)+ "");
Вывод: selectionArgs1:*5*1294429481330*5* (ТАК: не отображается * в источнике?)

StringBuffer d = new StringBuffer("selectionArgs2:");
d.append(deckId).append("").append(now).append("").append(level).append("");
Log.d(TAG, d.toString());
Вывод: selectionArgs2:*5*1294429481330*5*


person Phyrum Tea    schedule 05.01.2011    source источник
comment
выведите обе строки в logcat и сравните их.   -  person techiServices    schedule 06.01.2011
comment
@Phyrum Tea: неожиданно они должны вернуть те же результаты.   -  person CommonsWare    schedule 06.01.2011
comment
@sugarynugs: я установил там точку останова, чтобы скопировать SQL-запрос, и заменил значения вручную, скопировал базу данных из эмулятора и выполнил запрос с помощью sqlite3. Он дает правильные результаты. Я просмотрел исходный код rawQuery до нативных частей, кажется, все в порядке. Когда я вернусь домой после работы, я по-новому взгляну на проблему.   -  person Phyrum Tea    schedule 06.01.2011
comment
Я напечатал оба запроса в журнал и сравнил их в текстовом редакторе. После замены? символы со значениями, они оба одинаковы. Я использую неподготовленный и могу вернуться к проблеме позже. По крайней мере, другие подготовленные операторы в моем приложении работают. Спасибо за помощь.   -  person Phyrum Tea    schedule 06.01.2011
comment
@Phyrum, не могли бы вы опубликовать схему для таблицы «c»?   -  person martin clayton    schedule 07.01.2011
comment
Я думал о значениях NULL, которые могут иметь значение, но все они не равны нулю. Создать карты таблицы (_ID Integer первичный ключ, deck_id Integer, text_a, текст side_b, text atem_c, site_d текст, side_a_type integer, side_b_type integer, side_c_type integer, side_deger_deger, integer_deger, integer_deger, integer_deger, site_fie_deger, integer_deger, site_fie, site_fie, site_fie_deger, site_fie, site_fie, site_fie, site_fie, site_fie, integer_f ,status INTEGER,flag INTEGER,last_date INTEGER,next_date INTEGER,пробел INTEGER,созданный INTEGER,модифицированный INTEGER,last_right   -  person Phyrum Tea    schedule 07.01.2011
comment
... INTEGER,last_wrong INTEGER,review_date INTEGER,right_count INTEGER,wrong_count INTEGER,card_order INTEGER,active INTEGER,selected INTEGER); -- слишком долго.   -  person Phyrum Tea    schedule 07.01.2011
comment
Соответствует ли Long.toString(deckId) sb.append(deckId) и т.д.? Чтобы каждый запрос выдавал разные результаты, строки запроса должны каким-то образом отличаться.   -  person techiServices    schedule 07.01.2011


Ответы (1)


Я подозреваю, что это как-то связано с сходством типов, но мне не удалось воспроизвести выдайте именно так, как вы описываете.

Аффинитивное поведение может повлиять на выражения сравнения, поэтому «неподготовленный»

next_date < 12345678

может не быть не эквивалентным «подготовленному»:

next_date < '12345678'

Обратите внимание на подразумеваемый строковый тип данных, применяемый привязкой «rawQuery» — rawQuery* javadoc говорит:

Значения будут связаны как строки.

Я пытался приготовить тестовый пример с полем next_date INTEGER безрезультатно. Но если поле оставить нетипизированным, например:

CREATE TABLE cards ( next_date );

INSERT INTO cards SELECT 1234;
INSERT INTO cards SELECT '1234';

SELECT 'int', typeof( next_date ), next_date FROM cards WHERE next_date < 1234;
SELECT 'str', typeof( next_date ), next_date FROM cards WHERE next_date < '1234';

Затем можно увидеть различное поведение сходства - результат:

str|integer|1234

(Возможно, это комментарий, но его легче читать в формате ответа.)

*http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#rawQuery(java.lang.String,%20java.lang.String[])

person martin clayton    schedule 07.01.2011
comment
Я подозреваю, что в том же направлении, rawQuery связывается только со строками, а у меня есть целые числа. Это означает, что я не могу доверять подготовленным операторам с целыми числами? - person Phyrum Tea; 07.01.2011
comment
Я принимаю ваш намек, после просмотра sqlite.org/datatype3.html это, безусловно, проблема с использованием подготовленный оператор, если у вас есть не строки, участвующие в сравнении. См. часть 3.4 Сравнительный пример - person Phyrum Tea; 07.01.2011
comment
Но это не полностью объясняет поведение, потому что целое число находится в первом правиле. - person Phyrum Tea; 07.01.2011
comment
@Phyrum - я согласен, это ни в коем случае не полный ответ. Возможно, стоит попробовать next_date ‹ CAST( ? AS INTEGER ), чтобы увидеть, имеет ли это какое-то значение. - person martin clayton; 07.01.2011
comment
Этот CAST сделал это! Большое спасибо! - person Phyrum Tea; 08.01.2011