为什么Python的Sqlite3模块正确地解析了这个参数替换的第一个实例,之后没有?缓存?

时间:2013-12-26 00:57:06

标签: python-2.7 sqlite python-db-api

我有一个Sqlite3表,其中LastUpdated列包含格式为"2013-12-24 07:11:21"的UTC日期时间,并且该表中的所有行都在2天前更新。

我想编写一个SELECT语句,只返回一段时间内未更新的行:

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

我正在尝试使用sqlite3标准库从Python运行此查询,我希望过时的时间段是可变的。为了安全起见,我尝试使用sqlite3 standard lib documentation中提到的参数替换来使用变量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行,而不是所有行的预期结果。

当我重新启动计算机时,第一次看起来查询工作正常,但是如果我运行带有一个delta值的python脚本,只要我更改delta值,结果就会继续为运行查询的第一个实例。此外,如果我写两个SELECT语句,其中query1设置为'-4 days',它应该不返回'-1 days'处的{2}返回所有行,然后在运行脚本一次后,我切换那些值查询时,查询的输出不会切换。

我认为这可能是不正确的SQL查询,所以我尝试硬编码增量并在Sqlite3 shell中运行查询。正如我期望的那样工作,所以查询没有错。

然后我尝试将变量stale_delta_parameter'-n days'展开到DATETIME('now', '-n days'),以防参数替换在Sqlite的特殊DATETIME()函数中无法正常工作。奇怪的行为没有改变。

在Sqlite3标准库或Python DB-API中是否存在某种缓存,可能会阻止更新传递给底层数据库的查询?

我在文档中找不到任何东西,但这是我能想出的唯一理论,似乎符合这种行为。

我试图找到一种方法来打印从Python传递到db的已组装查询,因此我可以验证db没有获得查询的更新版本,但我找不到任何类型的查询从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 个答案:

答案 0 :(得分:1)

来自SQLite documentation

  

“variable”或“parameter”标记在表达式中为使用sqlite3_bind()C / C ++接口系列填充的值指定占位符。

这些接口包括基本类型(字符串,数字,blob),但不包括datetime等函数。

实现目标的一种方法是在unixepochjulianday中提供偏移量,并重新格式化查询以进行算术减法。

但是,您展示的第一个参数化版本应该可行;它在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
>