我有一个包含2列的postgres表,我在查询中使用该表:
start_date_detail: date
flex: jsonb
弹性字段示例:
{
"communication": [
{
"remind_on": "mxmw@cxla.nl",
"type": "email",
"remind_date": -150
},
{
"remind_on": "+31612345678",
"type": "sms",
"remind_date": -360
}
]
}
我需要选择所有提醒日期都在上周的记录,因此(伪代码):
(now() - 1-week) < (start_date_detail + remind_date) < now()
如何通过sqlalchemy来实现这一点?
因为它是查询中的计算值,所以我不知道该怎么做。 在postgres中,我提出了这个建议,并且可行:
SELECT * FROM time_item
WHERE
(start_date_detail + INTERVAL '1 second' * (flex->'communication'->0->>'remind_date')::numeric <= NOW())
OR (start_date_detail + INTERVAL '1 second' * (flex->'communication'->1->>'remind_date')::numeric <= NOW())
如何将其放入sqlalchemy?
还有一件事: 在上面的查询中,我将每个通讯项添加到where子句中。如何使它更灵活?那就是我不需要为每个通讯项都放一个where子句。
答案 0 :(得分:2)
您可以使用jsonb_array_elements()
将数组扩展为一组jsonb
元素,然后可以在谓词中使用。 SQLAlchemy通过使用alias支持将函数表达式作为可选函数。使用诸如
In [4]: class TimeItem(Base):
...: __tablename__ = 'time_item'
...: id = Column(Integer, primary_key=True)
...: start_date_detail = Column(Date)
...: flex = Column(JSONB)
...:
查询看起来像
In [39]: session.query(TimeItem).\
...: select_from(TimeItem,
...: func.jsonb_array_elements(TimeItem.flex['communication']).
...: alias('comm')).\
...: filter((TimeItem.start_date_detail +
...: timedelta(seconds=1) *
...: column('comm', type_=JSONB)['remind_date'].
...: astext.
...: cast(Integer)).
...: between(func.now() - timedelta(weeks=1),
...: func.now())).\
...: all()
然后,您可以调整谓词以适合您的需求–我尝试按照您的示例进行操作,因为与现在之前的一周相比,remind_date
被解释为与start_date_detail
的偏移秒数。当查询诸如TimeItem
之类的实体时,SQLAlchemy会基于对象身份进行自身的重复数据删除,因此查询可以省略SQL端DISTINCT,或者将数组元素移动到EXISTS子查询表达式中,等等。