【问题标题】:Getting results between two dates in PostgreSQL在 PostgreSQL 中获取两个日期之间的结果
【发布时间】:2012-04-27 13:43:02
【问题描述】:

我有下表:

+-----------+-----------+------------+----------+
| 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)

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

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

【问题讨论】:

  • @MarcoMariani 我希望它能够像示例中一样工作。
  • 这个问题并没有真正说明“匹配”是什么意思。包含?包含在?重叠?完全匹配?

标签: sql postgresql date overlap


【解决方案1】:

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

【讨论】:

  • 为什么不呢?这种格式取决于客户端的区域设置,数据库将其存储在几个字节中,没有任何格式。
【解决方案2】:

要让查询在任何区域设置下都能正常工作,请自己考虑formatting the date

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');

【讨论】:

    【解决方案3】:
     SELECT *
       FROM mytable
      WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE);
    

    Datetime functions 是文档中的相关部分。

    【讨论】:

    • 这不是我的直接问题,但是,使用 OVERLAPS 节省了我的时间。非常感谢:)
    【解决方案4】:

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

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

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

    这对我来说有时比OVERLAPS 更快——这是另一种好方法(如@Marco already provided)。

    注意细微的差异 (per documentation):

    OVERLAPS 自动取该对中较早的值作为 开始。每个时间段都被认为代表半开 间隔 start &lt;= time &lt; end,除非 start 和 end 相等,其中 如果它代表那个单一的时间瞬间。这意味着例如 只有一个共同端点的两个时间段不重叠。

    我的大胆强调。

    性能

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

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

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

    注意两列的倒序。详细解释:

    【讨论】:

      【解决方案5】:

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

      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')
      

      【讨论】:

        【解决方案6】:

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

        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'
        

        【讨论】:

          【解决方案7】:

          没有冒犯,但为了检查 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建议的第一个

          【讨论】:

            【解决方案8】:
            SELECT *
            FROM ecs_table
            WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE + interval '1');
            

            【讨论】:

              【解决方案9】:

              让我们试试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-03-12
                • 2021-10-04
                • 1970-01-01
                • 2015-01-08
                • 1970-01-01
                • 2018-01-11
                • 1970-01-01
                • 2019-02-11
                • 1970-01-01
                相关资源
                最近更新 更多