69

我想在PostgreSQL 数据库中获取两个日期(包括它们)之间的天数列表。例如,如果我有:

  • 开始日期:2012年6月29日
  • 结束日期:2012 年 7 月 3 日

那么结果应该是:

29 june 2012
30 june 2012 
1 july 2012 
2 july 2012 
3 july 2012

在 PostgreSQL 中执行此操作的最佳方法是什么?

谢谢。

4

8 回答 8

116
select CURRENT_DATE + i 
from generate_series(date '2012-06-29'- CURRENT_DATE, 
     date '2012-07-03' - CURRENT_DATE ) i

甚至更短:

select i::date from generate_series('2012-06-29', 
  '2012-07-03', '1 day'::interval) i
于 2012-07-09T09:05:30.057 回答
44

作为timestamp

select generate_series('2012-06-29', '2012-07-03', '1 day'::interval);

    generate_series     
------------------------
 2012-06-29 00:00:00-03
 2012-06-30 00:00:00-03
 2012-07-01 00:00:00-03
 2012-07-02 00:00:00-03
 2012-07-03 00:00:00-03

或转换为date

select (generate_series('2012-06-29', '2012-07-03', '1 day'::interval))::date;

 generate_series 
-----------------
 2012-06-29
 2012-06-30
 2012-07-01
 2012-07-02
 2012-07-03
于 2012-09-22T10:34:37.913 回答
8

这应该这样做:

select date '2012-06-29' + i
from generate_series(1, (select date '2012-07-3' - date '2012-06-29')) i

如果您不想在子选择中重复 start_date,事情会变得更加复杂:

with min_max (start_date, end_date) as (
   values (date '2012-06-29', date '2012-07-3')
), date_range as (
  select end_date - start_date as duration
  from min_max
)
select start_date + i
from min_max
  cross join generate_series(1, (select duration from date_range)) i;

(有关“不重复”问题的更好版本,请参阅 maniek 的答案)

于 2012-07-09T08:12:31.207 回答
7
select generate_series('2012-06-29', '2012-07-03', '1 day'::interval)::date;
于 2015-02-07T13:15:35.827 回答
5

对于这样的事情,在系统中拥有一个日期表通常很方便。

就像数字表一样,它们比动态生成日期非常有用且使用起来更快,尤其是当您扩展到大型数据集时。

这种从 1900 年到 2100 年的日期表会非常小,因此存储空间不会太大。

编辑:不知道为什么这会被否决,它可能是最好的性能。此外,它还有许多其他优点。想要将订单链接到一个季度的业绩数据?它是表格之间的简单链接。(Order.OrderDate -> Dates.Date -> Dates.Quarter -> PerformanceTotal.Quarter) 等等。处理工作日也是一样的,比如一个月的最后一个工作日,或者上个月的第一个星期二。就像数字表一样,我强烈推荐它们!

于 2012-07-09T09:21:13.093 回答
0

如果您已经有要查询的数据库:

SELECT
   TO_CHAR(date_column,'DD Mon YYYY')
FROM
   some_table
WHERE
   date_column BETWEEN '29 Jun 2012' AND '3 JUL 2012'

GROUP BY date_column
ORDER BY date_column

这将导致:

"29 Jun 2012"
"30 Jun 2012"
"01 Jul 2012"
"02 Jul 2012"
"03 Jul 2012"
于 2012-07-09T08:20:47.410 回答
0

这个 PLpg/SQL 函数可以解决问题:

CREATE OR REPLACE FUNCTION getDateList(date1 date, date2 date)
RETURNS SETOF date AS
$BODY$
DECLARE
    count integer;
    lower_limit integer :=  0;
    upper_limit integer :=  date2 - date1;
BEGIN
    FOR count IN lower_limit..upper_limit LOOP
        RETURN NEXT date1 + count;
    END LOOP;
    RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
于 2012-07-09T08:22:48.337 回答
0

如果日期范围应来自表表达式,则可以使用以下构造:

DROP TABLE tbl ;
CREATE TABLE tbl (zdate date NOT NULL );
INSERT INTO tbl(zdate) VALUES( '2012-07-01') , ('2012-07-09' );

WITH mima AS (
        SELECT MIN(zdate)::timestamp as mi
        , MAX(zdate)::timestamp as ma
        FROM tbl
        )
SELECT generate_series( mima.mi, mima.ma, '1 day':: interval):: date
FROM mima
        ;

需要强制转换,因为 generate_series() 不接受日期参数。

于 2012-07-09T08:25:03.097 回答