具有starts_on和ends_on的对象最佳查询建议

时间:2012-12-03 01:18:26

标签: sql postgresql datetime date-range

我需要从包含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过滤我希望不退回该项目

1 个答案:

答案 0 :(得分:2)

查询

如果您希望starts_onends_on之间的时间段与START_DATEEND_DATE的传递时间段重叠,并且“结束”始终更晚而不是“开始”,所有涉及的列都是timestamp类型(而不是timedate),这个更简单的查询可以完成工作:

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

稍后澄清了这个问题。

索引

此查询的最佳索引是multi-column index,如:

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 types,有自己的运算符。但不适用于9.1。