postgresql daysdiff在按月分组的两个日期之间

时间:2014-09-09 09:58:48

标签: postgresql

我有一个包含日期列的表(start_date,end_date),我想计算这些日期之间的差异,并按月分组。

我能够在几天内获得日期,但我不知道如何在一个月内对此进行分组,有什么建议吗?

Table:
id       Start_date   End_date      days      
1234     2014-06-03   2014-07-05     32
12345    2014-02-02   2014-05-10     97

Expected results:
month  diff_days
2      26
3      30
4      31
5      10
6      27    
7      5

2 个答案:

答案 0 :(得分:1)

我认为您的预期输出数量有点偏差。您可能需要仔细检查。

我自己使用日历表,但此查询使用CTE和日期算法。避免硬编码日期'2014-01-01'和间隔365天很简单,但它使查询更难阅读,所以我只是直接使用这些值。

with your_data as (
  select date '2014-06-03' as start_date, date '2014-07-05' as end_date union all
  select '2014-02-02', '2014-05-10'
), calendar as (
  select date '2014-01-01' + (n || ' days')::interval calendar_date
  from generate_series(0, 365) n
)
select extract (month from calendar_date) calendar_month, count(*) from calendar
inner join your_data on calendar.calendar_date between start_date and end_date
group by calendar_month
order by calendar_month;
calendar_month  count
--
2               27
3               31
4               30
5               10
6               28
7               5

根据经验,您不应该单独按月分组 - 这样做可能会对来自不同年份的数据进行分组。这是一个更安全的版本,包括年份,并且还将输出限制为单个日历年。

with your_data as (
  select date '2014-06-03' as start_date, date '2014-07-05' as end_date union all
  select '2014-02-02', '2014-05-10' 
), calendar as (
  select date '2014-01-01' + (n || ' days')::interval calendar_date
  from generate_series(0, 700) n
)
select extract (year from calendar_date) calendar_year, extract (month from calendar_date) calendar_month, count(*) from calendar
inner join your_data on calendar.calendar_date between start_date and end_date
where calendar_date between '2014-01-01' and '2014-12-31'
group by calendar_year, calendar_month
order by calendar_year, calendar_month;

答案 1 :(得分:0)

SQL Fiddle

with min_max as (
    select min(start_date) as start_date, max(end_date) as end_date
    from t
), g as (
    select daterange(d::date, (d + interval '1 month')::date, '[)') as r
    from generate_series(
        (select date_trunc('month', start_date) from min_max),
        (select end_date from min_max),
        '1 month'
    ) g(d)
)
select *
from (
    select
        to_char(lower(r), 'YYYY Mon') as "Month",
        sum(upper(r) - lower(r)) as days
    from (
        select t.r * g.r as r
        from
            (
                select daterange(start_date, end_date, '[]') as r
                from t
            ) t
            inner join
            g on t.r && g.r
    ) s
    group by 1
) s
order by to_timestamp("Month", 'YYYY Mon')
;
  Month   | days 
----------+------
 2014 Feb |   27
 2014 Mar |   31
 2014 Apr |   30
 2014 May |   10
 2014 Jun |   28
 2014 Jul |    5

Range data types

Range functions and operators