I need to select from a table that has a starts_on field and an ends_on field.
I need to pass start date and end date for filtering and retrieving those objects.
At the moment it’s working and I use the following:
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
It looks a bit messy, but can’t see an easy way to simplify it. Any idea?
I’m using postgres 9.1 as dbms.
Edit:
starts_on | timestamp without time zone |
ends_on | timestamp without time zone |
Ex: if one entry has starts_on = ‘2012/02/02’ and ends_on ‘2012/02/05’ I want the following behavior:
- if I filter by start date 2012/01/01 and end date 2012/03/01 I want the item to be returned
- if I filter by start date 2012/02/04 and end date 2012/03/01 I want the item to be returned
- if I filter by start date 2012/02/05 and end date 2012/03/01 I want the item to be returned
- if I filter by start date 2012/02/04 and end date 2012/02/04 I want the item to be returned
- if I filter by start date 2012/02/06 and end date 2012/03/01 I want the item to NOT be returned
- if I filter by start date 2012/01/01 and end date 2012/02/01 I want the item to NOT be returned
Query
If you want all rows where the time period between
starts_onandends_onoverlaps with the passed time period ofSTART_DATEandEND_DATE, and "end" is always later than "start", and all involved columns are of typetimestamp(as opposed totimeordate), this simpler query does the job:Fits the question as later clarified.
Index
The best index for this query would be a multi-column index like:
Would work with
DESC / ASCalmost as well, because an index can be searched in both directions almost equally well.How do I figure?
The index is searched on the first condition
starts_on <= END_DATE, qualifying rows are at the beginning.From there, Postgres can take all rows that end late enough according to
ends_on >= START_DATE. Qualifying rows come first. Optimal index.But don’t just take my word – test performance with
EXPLAIN ANALYZE. Run a couple of times to exclude caching effects.There is also the
OVERLAPSoperator for the same purpose. Simplifies the logic, but isn’t superior otherwise.And there are the new
rangetypes in PostgreSQL 9.2, with their own operators. Not for 9.1 though.