我的一位用户希望回答这个问题:
“在2005年至2010年的任何一个月中,有哪些要求存在?”
数据库表“request”有2列,start_date
和end_date
,代表请求生命周期的间隔。
SQLAlchemy模型如下所示:
class Request(SomeBaseModel):
...
start_date = db.Column(db.Date, default=date.today)
end_date = db.Column(db.Date, default=in_one_year)
然后我有一个在Python中动态获得5年零一个月的过程:
`initial_date`, five_years_later, month_number = getTimePeriod()
根据这些参数,我必须列出initial_date
和five_years_later
之间开始或结束的所有请求。通过将start_date
和end_date
与initial_date
和five_years_later
进行比较,我可以轻松完成这项工作。
然而,困难的部分是仅获取在特定月份内存在的请求,而该月份也是(initial_date
,five_years_later
)间隔的一部分。规则是:
initial_date
,five_years_later
)间隔内。我可以通过为(initial_date
,five_years_later
)间隔的每一年生成每个月的开始日期和结束日期来做到这一点,然后检查这些对中的任何一对是否与请求重叠一生:
filters = []
for year in range(initial_date, five_years_later + 1):
month_start_date = datetime(year, month, 1)
month_end_date = datetime(year, month, calendar.mdays[month])
filters.append(
(requeest.start_date <= month_end_date) &
(request.end_date >= month_start_date)
)
is_active = functools.reduce(operator.or_, filters)
auth_requests = auth_requests.filter(is_active)
然而,我的胆量告诉我有更好的方法。
SQLAlchemy查询将是最好的答案,但Postgres的SQL版本可以。
答案 0 :(得分:2)
以下是我解决问题的方法。
无论哪种 - 请求的持续时间应大于等于1年。
或者 - start_date必须在三月期间或之后>> end_date应在三月或之前。
AND
start_date / end_date必须在范围内(2005,2010)
此postgres查询将检查条件:
select * from request
where 1 =
CASE
WHEN extract(year from age(end_date,start_date)) >= 1 THEN 1
WHEN (extract(month from start_date)::integer <= 3
AND extract(month from end_date)::integer >= 3 )
AND extract(year from age(end_date,start_date)) < 1 THEN 1
WHEN (extract(month from start_date)::integer >= 3
AND extract(month from end_date)::integer <= 3 )
AND extract(year from age(end_date,start_date)) < 1 THEN 1
ELSE 0
END
AND ((extract(year from start_date)::integer >= 2005
and extract(year from start_date)::integer <= 2010)
OR (extract(year from end_date)::integer >= 2005
and extract(year from end_date)::integer <= 2010))
;
编辑:这比我第一次意识到的要复杂得多。编辑查询以满足所有条件。
答案 1 :(得分:1)
实际上,您在问题中的建议构建了一组过滤器,用于评估开始日期和结束日期与相关月份之间的交集。因此,您将月份,开始和结束日期转换为大约五个过滤器(取决于边界条件),然后使用或运算符。 假设您的列已正确编入索引(或者如果不是全表扫描是您的数据的正确答案),我认为任何事情都不会比这更好。您的查询为Postgres提供了一组要比较的时间间隔。每行最多需要处理一次。 对于这个理想的问题。 所以我的答案是你已经找到了最好的方法。可能有其他方法具有相同的性能特征,但您所拥有的内容很容易理解并且表现良好。