Getting date list in a range in PostgreSQL
我想在PostgreSQL数据库中获取两个日期(包括它们)之间的日期列表。 例如,如果我有:
- 开课日期:2012年6月29日
- 截止日期:2012年7月3日
那么结果应该是:
1 2 3 4 5 | 29 june 2012 30 june 2012 1 july 2012 2 july 2012 3 july 2012 |
在PostgreSQL中执行此操作的最佳方法是什么?
谢谢。
1 2 3 | SELECT CURRENT_DATE + i FROM generate_series(DATE '2012-06-29'- CURRENT_DATE, DATE '2012-07-03' - CURRENT_DATE ) i |
甚至更短:
1 2 | SELECT i::DATE FROM generate_series('2012-06-29', '2012-07-03', '1 day'::INTERVAL) i |
作为
1 2 3 4 5 6 7 8 9 | 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 |
或者转换为
1 2 3 4 5 6 7 8 9 | 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 |
这应该这样做:
1 2 | SELECT DATE '2012-06-29' + i FROM generate_series(1, (SELECT DATE '2012-07-3' - DATE '2012-06-29')) i |
如果你不想在subselect中重复start_date,那么事情就会变得复杂一些:
1 2 3 4 5 6 7 8 9 | 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的答案,以获得更好的"无重复"问题)
对于这样的事情,在系统中有一个日期表通常很方便。
就像数字表一样,它们可以非常有用并且比使用生成日期更快,特别是当您扩展到大型数据集时。
从1900年到2100年这样的日期表将非常小,因此存储空间不大。
编辑:Dunno为什么这会被投票,它可能是最好的表现。此外,它还有许多其他优点。想要将订单链接到季度绩效数字?它是表之间的简单链接。 (Order.OrderDate - > Dates.Date - > Dates.Quarter - > PerformanceTotal.Quarter)等处理工作日的情况相同,例如一个月的最后一个工作日,或上个月的第一个星期二。像数字表一样,我强烈推荐它们!
1 | SELECT generate_series('2012-06-29', '2012-07-03', '1 day'::INTERVAL)::DATE; |
如果日期范围应来自表表达式,则可以使用以下构造:
1 2 3 4 5 6 7 8 9 10 11 12 | 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()不接受日期参数。
这个PLpg / SQL函数可以解决这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
如果您已经拥有要查询的数据库:
1 2 3 4 5 6 7 8 9 | 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 |
这将导致:
1 2 3 4 5 | "29 Jun 2012" "30 Jun 2012" "01 Jul 2012" "02 Jul 2012" "03 Jul 2012" |