我有两个表'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
因此可以进行比较,但我不确定该方法是否有效。
答案 0 :(得分:3)
首先让我解释一下你为什么尝试不起作用。 SQLAlchemy只是编写SQL查询的一种便捷方式,但所有查询都发生在远程端。 SQLAlchemy列是特殊对象,其__eq__
,__gt__
等方法被覆盖而不返回True
或False
,但其他特殊对象记住了它们被比较的对象是什么以后可以生成适当的SQL语句。添加等同样如此:自定义__add__
,__sub__
方法不返回数字或连接字符串,而是返回生成sql语句的对象。你可以比较/添加它们到字符串,整数等,其他列,select语句,mysql函数调用等,但不能像timedeltas那样特殊的python对象。(简化,技术上可能不是100%正确; ))
所以你可以做的是:
between
查询将起作用(使用2
代替delta) 更新:我已经玩了一点点,以某种方式确实有效,甚至还有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
如果你有更好的主意,我会接受你的回答。