Почему модуль Python Sqlite3 правильно анализирует первый экземпляр этой подстановки параметров, а затем нет? Кэширование?

У меня есть таблица Sqlite3, которая имеет LastUpdated столбец, содержащий дату и время UTC, отформатированный как "2013-12-24 07:11:21" и все строки в этой таблице были обновлены 2 дня назад.

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

SELECT LastUpdated FROM UserToken WHERE DATETIME(LastUpdated) < DATETIME('now', '-4 days');

Я пытаюсь выполнить этот запрос из Python, используя стандартную библиотеку sqlite3, и хочу, чтобы устаревший период был переменным. В целях безопасности я попытался использовать подстановку параметров, упомянутую в стандартной документации lib для sqlite3, чтобы использовать переменную stale_delta_parameter:

dbcursor.execute("SELECT LastUpdated FROM UserToken WHERE TokenValid = 1 AND DATETIME(LastUpdated) < DATETIME('now', ?)", (stale_delta_parameter,))

Первый раз, когда я его запустил, я установил stale_delta_parameter = '-4 days' и он правильно вернул ноль строк. Затем я изменил значение stale_delta_parameter на "-1 дней" и запустил запрос. Вместо ожидаемого результата всех строк запрос продолжал возвращать 0 строк.

Когда я перезагружаю компьютер, кажется, что запрос работает нормально с первого раза, но, опять же, если я запускаю скрипт python с одним дельта-значением, как только я изменяю дельта-значение, результаты продолжают оставаться значениями из первого экземпляра. выполнения запроса. Кроме того, если я напишу два оператора SELECT, где query1 установлен в '-4 days' который не должен возвращать строки и query2 в '-1 days' который должен вернуть все строки, а затем, после запуска сценария, я переключаю значения в этих запросах, выходные данные запросов не переключаются.

Я подумал, что это могут быть неправильные запросы SQL, поэтому я попытался жестко запрограммировать дельту и запустить запрос в оболочке Sqlite3. Работает так, как я ожидаю каждый раз, поэтому запрос не ошибается.

Затем я попытался расширить переменную stale_delta_parameter от '-n days' в DATETIME('now', '-n days') на всякий случай подстановка параметров не работала правильно внутри специального Sqlite DATETIME() функция. Странное поведение не изменилось.

Существует ли какое-либо кэширование в стандартной библиотеке Sqlite3 или в DB-API Python, которое может помешать обновлению запроса, передаваемого в базовую базу данных?

В документах я ничего не могу найти, но это единственная теория, которую я могу придумать, которая, кажется, соответствует этому поведению.

Я попытался найти способ напечатать собранный запрос, который передается в БД из Python, поэтому я могу убедиться, что БД не получает обновленную версию запроса, но я не могу найти какой-либо метод для печати собранный запрос от dbcursor.execute(...),

Вот фактический код:

til_user_tokens_go_stale = '4 days'
stale_delta_parameter = "DATETIME('now','-%s')" % til_user_tokens_go_stale  
dbcursor.execute('''
                 SELECT UserToken, UserID, AppID 
                 FROM UserToken 
                 WHERE TokenValid = 1 AND DATETIME(LastUpdated) < ?
                 ''', (stale_delta_parameter,))
all_tokens = dbcursor.fetchall()
print len(all_tokens) # For debugging, shows me how many rows are returned

1 ответ

Из документации по SQLite:

Токен "variable" или "parameter" указывает местозаполнитель в выражении для значения, которое заполняется во время выполнения с использованием семейства интерфейсов C/C++ sqlite3_bind ().

Эти интерфейсы включают базовые типы (строки, числа, BLOB-объекты), но не такие функции, как datetime,

Один из способов добиться того, что вам нужно, - предоставить смещение в unixepoch или же juliandays, и переформатировать запрос, чтобы сделать арифметическое вычитание.

Однако первая параметризованная версия, которую вы показали, должна работать; это делает в Lua:

> db = sqlite3.open(':memory:')
> db:execute'create table t (d);'
> db:execute"insert into t values ('2013-12-26 14:20:00');"
> st = db:prepare "select * from t where d < datetime('now',?);"
> st:bind(1,'+1 day');
> for row in st:urows() do print (row) end
2013-12-26 14:20:00
> st:bind(1,'-1 day');
> for row in st:urows() do print (row) end
> 
Другие вопросы по тегам