使用SQLAlchemy在两秒内过滤对象

时间:2010-05-28 22:56:41

标签: python database datetime sqlalchemy

我有两个表'date'列。一个持有(名称,日期),另一个持有(日期,p1,p2)。给定一个名称,我想使用表1中的日期来查询表2中的p1和p2;如果表1中的日期在表2中的日期的两秒内,则匹配应该发生。

如何使用SQLAlchemy完成此操作?

我已尝试(未成功)使用between运算符并使用以下子句:

td = datetime.timedelta(seconds=2)
q = session.query(table1, table2).filter(table1.name=='my_name').\
    filter(between(table1.date, table2.date - td, table2.date + td))

有什么想法吗?

修改 我已设法使用以下方法解决问题:

from sqlalchemy.sql import between
import datetime
# [all other relevant imports]

td = datetime.timedelta(seconds=2)
t1_entry = session.query(table_1).filter(table_1.name == 'the_name').first()
if t1_entry is not None:
 tmin = t1_entry.date - td
 tmax = t1_entry.date + td
 t2_entry = session.query(table_2).filter(between(table_2.date, tmin, tmax)).first()
 return (t1_entry, t2_entry)
return None

因此可以进行比较,但我不确定该方法是否有效。

3 个答案:

答案 0 :(得分:3)

首先让我解释一下你为什么尝试不起作用。 SQLAlchemy只是编写SQL查询的一种便捷方式,但所有查询都发生在远程端。 SQLAlchemy列是特殊对象,其__eq____gt__等方法被覆盖而不返回TrueFalse,但其他特殊对象记住了它们被比较的对象是什么以后可以生成适当的SQL语句。添加等同样如此:自定义__add____sub__方法不返回数字或连接字符串,而是返回生成sql语句的对象。你可以比较/添加它们到字符串,整数等,其他列,select语句,mysql函数调用等,但不能像timedeltas那样特殊的python对象。(简化,技术上可能不是100%正确; ))

所以你可以做的是:

  • 使数据库中的值为整数,例如unix时间戳。这样,您的between查询将起作用(使用2代替delta)
  • 使用数据库端函数将日期时间格式日期转换为unix时间戳,然后进行比较。

更新:我已经玩了一点点,以某种方式确实有效,甚至还有Interval数据类型。但至少在这里它不能正常工作:

MySQL的:

>>> db.session.execute(db.select([User.date_joined, User.date_joined + timedelta(seconds=2)], limit=1)).fetchall()
[(datetime.datetime(2009, 7, 10, 20, 47, 33), 20090710204733.0)]
>>> db.session.execute(db.select([User.date_joined, User.date_joined + 2], limit=1)).fetchall()
[(datetime.datetime(2009, 7, 10, 20, 47, 33), 20090710204735.0)]
>>> db.session.execute(db.select([User.date_joined+0, User.date_joined + 2], limit=1)).fetchall()
[(20090710204733.0, 20090710204735.0)]

SQLite的:

>>> db.session.execute(db.select([User.date_joined, User.date_joined + timedelta(seconds=2)], limit=1)).fetchall()
TypeError: expected string or buffer
>>> db.session.execute(db.select([User.date_joined, User.date_joined + 2], limit=1)).fetchall()
[(datetime.datetime(2010, 5, 28, 23, 8, 22, 476708), 2012)]
>>> db.session.execute(db.select([User.date_joined+0, User.date_joined + 2], limit=1)).fetchall()
[(2010, 2012)]

我不知道为什么第一个在MySQL上失败以及为什么它会返回浮点数。 SQLite错误似乎是因为SQLite does not have a DATETIME data type and SQLAlchemy stores it as a string

你将不得不玩一点,也许你会找到一种方法 - 但我认为保持真正的dbms独立整数方法将是唯一可行的方法。

答案 1 :(得分:1)

方法是将日期转换为unix时间戳。

在最近的一段代码中,我成功使用了以下几行:

from sqlalchemy.sql import func
...
q = q.join(q2, func.abs(func.unix_timestamp(rssi1.datetime)-func.unix_timestamp(q2.c.datetime)) <=2 )

但请注意,func.xxx只是将xxx作为字符串复制到查询中,因此数据库必须支持xxx函数。这个例子适用于MySQL。

答案 2 :(得分:0)

在这个问题开放一段时间之后,到目前为止的方法是我提出的方法:

from sqlalchemy.sql import between
import datetime
# [all other relevant imports]

td = datetime.timedelta(seconds=2)
t1_entry = session.query(table_1).filter(table_1.name == 'the_name').first()
if t1_entry is not None:
 tmin = t1_entry.date - td
 tmax = t1_entry.date + td
 t2_entry = session.query(table_2).filter(between(table_2.date, tmin, tmax)).first()
 return (t1_entry, t2_entry)
return None

如果你有更好的主意,我会接受你的回答。