0

我需要从具有starts_on字段和ends_on字段的表中进行选择。
我需要传递开始日期和结束日期来过滤和检索这些对象。

目前它正在工作,我使用以下内容:

SELECT * FROM ***
WHERE ((starts_on >= START_DATE AND starts_on <= END_DATE) OR
       (ends_on >= START_DATE AND ends_on <= END_DATE) OR
       (starts_on <= END_DATE AND ends_on >= END_DATE))
ORDER BY starts_on, id

它看起来有点凌乱,但看不到简化它的简单方法。任何的想法?
我使用 postgres 9.1 作为 dbms。

编辑:

 starts_on   | timestamp without time zone | 
 ends_on     | timestamp without time zone | 

例如:如果一个条目有 starts_on = '2012/02/02' 和 ends_on '2012/02/05' 我想要以下行为:

  • 如果我按开始日期 2012/01/01 和结束日期 2012/03/01 过滤,我希望退回该项目
  • 如果我按开始日期 2012/02/04 和结束日期 2012/03/01 过滤,我希望退回该项目
  • 如果我按开始日期 2012/02/05 和结束日期 2012/03/01 过滤,我希望退回该项目
  • 如果我按开始日期 2012/02/04 和结束日期 2012/02/04 过滤,我希望退回该项目
  • 如果我按开始日期 2012/02/06 和结束日期 2012/03/01 过滤,我希望不退回该项目
  • 如果我按开始日期 2012/01/01 和结束日期 2012/02/01 过滤,我希望不退回该项目
4

1 回答 1

2

询问

如果您希望所有行之间的时间段与starts_onandends_on的传递时间段重叠,START_DATE并且END_DATE“end”总是晚于“start”,并且所有涉及的列都是类型timestamp(而不是timeor date),这个更简单的查询确实工作:

SELECT *
FROM   tbl
WHERE  starts_on <= END_DATE
AND    ends_on   >= START_DATE
ORDER  BY starts_on, id;

适合稍后澄清的问题。

指数

此查询的最佳索引是多列索引,例如:

CREATE INDEX tbl_range_idx ON tbl (starts_on, ends_on DESC)

几乎也可以使用DESC / ASC,因为可以在两个方向上几乎同样好地搜索索引。

我怎么算?

在第一个条件上搜索索引starts_on <= END_DATE,符合条件的行在开头。
从那里,Postgres 可以根据ends_on >= START_DATE. 排位赛排在第一位。最优指数。

但不要只相信我的话 - 测试性能EXPLAIN ANALYZE。运行几次以排除缓存效果。

也有OVERLAPS出于相同目的的操作员。简化了逻辑,但在其他方面并不优越。

PostgreSQL 9.2 中还有新的range类型,它们有自己的运算符。但不适用于 9.1。

于 2012-12-03T01:31:43.850 回答