41

我有下表:

+-----------+-----------+------------+----------+
| id        | user_id   | start_date | end_date |
| (integer) | (integer) | (date)     | (date)   |
+-----------+-----------+------------+----------+

字段start_dateend_date保存日期值,如YYYY-MM-DD.

此表中的条目可能如下所示:(1, 120, 2012-04-09, 2012-04-13)

我必须编写一个查询,该查询可以获取与某个时期匹配的所有结果。

问题是,如果我想从 to 获取结果2012-01-012012-04-12即使有一个带有start_date = "2012-04-09"and的条目,我也会得到 0 个结果end_date = "2012-04-13"

4

9 回答 9

67
 SELECT *
   FROM mytable
  WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE);

日期时间函数是文档中的相关部分。

于 2012-04-16T09:13:49.143 回答
37

假设您想要所有“重叠”的时间段,即所有至少有一天的时间段。

试着在一条直线上设想时间段,然后在你眼前移动它们,你会看到必要的条件。

SELECT *
FROM   tbl
WHERE  start_date <= '2012-04-12'::date
AND    end_date   >= '2012-01-01'::date;

这对我来说有时比OVERLAPS- 这是另一种好方法(正如@Marco已经提供的那样)。

请注意细微差别根据文档):

OVERLAPS自动将较早的值作为开始。每个时间段都被认为代表半开区间start <= time < end,除非开始和结束相等,在这种情况下它代表单个时间瞬间。这意味着例如只有一个共同端点的两个时间段不重叠。

大胆强调我的。

表现

对于大表,正确的索引可以提高性能(很多)。

CREATE INDEX tbl_date_inverse_idx ON tbl(start_date, end_date DESC);

如果您有其他选择条件,可能与另一个(前导)索引列一起使用。

注意两列的相反顺序。详细解释:

于 2012-04-16T13:05:56.173 回答
23

只是有同样的问题,并以这种方式回答,如果这有帮助的话。

select * 
from table
where start_date between '2012-01-01' and '2012-04-13'
or    end_date   between '2012-01-01' and '2012-04-13'
于 2013-04-27T13:46:02.877 回答
3

要在任何区域设置中进行查询,请考虑自行格式化日期

SELECT * 
  FROM testbed 
 WHERE start_date >= to_date('2012-01-01','YYYY-MM-DD')
   AND end_date <= to_date('2012-04-13','YYYY-MM-DD');
于 2012-04-16T08:27:46.317 回答
0

查看它不起作用的日期——那些日期小于或等于 12 的日期——我想知道它是否将日期解析为 YYYY-DD-MM 格式?

于 2012-04-16T08:17:51.717 回答
0

您必须使用日期部分获取方法:

SELECT * FROM testbed WHERE start_date  ::date >= to_date('2012-09-08' ,'YYYY-MM-DD') and date::date <= to_date('2012-10-09' ,'YYYY-MM-DD')
于 2012-10-09T07:01:34.263 回答
0

没有冒犯,但为了检查 sql 的性能,我执行了一些上面提到的解决方案 a pgsql。

让我与您分享我遇到的前 3 种解决方案方法的统计数据。

1) 花费:1.58 毫秒平均

2) 花费:2.87 毫秒平均

3) 花费:3.95 毫秒平均

现在试试这个:

 SELECT * FROM table WHERE DATE_TRUNC('day', date ) >= Start Date AND DATE_TRUNC('day', date ) <= End Date

现在这个解决方案花了:1.61 Avg。

最好的解决方案是marco-mariani建议的第一个

于 2014-09-12T06:54:56.983 回答
0
SELECT *
FROM ecs_table
WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE + interval '1');
于 2018-01-22T11:39:57.837 回答
0

让我们试试range数据类型。

- 样本数据。

begin;
create temp table tbl(id  serial, user_id integer, start_date date, end_date date);
insert into tbl(user_id, start_date, end_date) values(1, '2012-04-09', '2012-04-13');
insert into tbl(user_id, start_date, end_date) values(1, '2012-01-09', '2012-04-12');
insert into tbl(user_id, start_date, end_date) values(1, '2012-02-09', '2012-04-10');
insert into tbl(user_id, start_date, end_date) values(1, '2012-04-09', '2012-04-10');
commit;

添加一个新的日期范围列。

begin;
alter table tbl add column tbl_period daterange ;
update tbl set tbl_period = daterange(start_date,end_date);
commit;

--现在测试时间。

select * from tbl
    where tbl_period && daterange('2012-04-10' ::date, '2012-04-12'::date);

返回:

 id | user_id | start_date |  end_date  |       tbl_period
----+---------+------------+------------+-------------------------
  1 |       1 | 2012-04-09 | 2012-04-13 | [2012-04-09,2012-04-13)
  2 |       1 | 2012-01-09 | 2012-04-12 | [2012-01-09,2012-04-12)

进一步参考:https ://www.postgresql.org/docs/current/functions-range.html#RANGE-OPERATORS-TABLE

于 2021-10-19T07:11:59.700 回答