2017-06-29 112 views
1

我在SQL表是STARTDATE兩列日期和結束日期如何獲得月,年和日在PostgreSQL的兩個日期

Startdate   Enddate 
27-12-2015 22:30 03-01-2016 19:30 
01-01-2016 12:45 09-02-2016 18:30 

我想要得到的結果表像

Startdate   Enddate   Month  year days 
27-12-2015 22:30 03-01-2016 19:30 Dec  2015 5 
27-12-2015 22:30 03-01-2016 19:30 Jan  2016 3 
01-01-2016 12:45 09-02-2016 18:30 Jan  2016 31 
01-01-2016 12:45 09-02-2016 18:30 Feb  2016 9 
+0

應該是什麼 「月」 值如startdate = 2017-01-01和enddate = 2017-06-29?或者startdate = 2010-04-01和enddate = 2017-02-01的年份值? –

+0

@a_horse_with_no_name第一個月值應爲一月,二月,三月,四月,五月,六月,在一個月的日子裏,包括開始日期和結束日期。而第二個日期年份分別爲2010,2011,2012,2013,2014,2015,2016,2017,分別爲日期和日期。 – dhS

+0

請在添加要求之前添加評論。 – dhS

回答

1
之間

粗略的解決方案是生成所有日子,然後聚合(計數)它們。它有效,但在記憶中很粗糙。如果這不是關鍵,這個解決方案肯定會奏效。另一種選擇是生成一個月份系列,並在有很多條件的情況下進行日差,如果性能很關鍵。

SELECT 
    dates.startdate::DATE, 
    dates.enddate::DATE, 
    to_char(days.s, 'Mon') AS mon, 
    to_char(days.s, 'YYYY') AS yr, 
    count(1) AS d 
FROM dates 
CROSS JOIN LATERAL (
    SELECT * FROM generate_series(dates.startdate, dates.enddate, INTERVAL '1 day') s 
) days 
GROUP BY 1, 2, 3, 4 

在任何情況下,這裏是第二個變體,通過幾個月循環,而不是(更快,更難理解):

SELECT 
    dates.startdate::DATE, 
    dates.enddate::DATE, 
    to_char(months.startdate, 'Mon') AS mon, 
    to_char(months.startdate, 'YYYY') AS yr, 
    least(
     months.enddate::DATE - dates.startdate::DATE + 1, -- takes care of first month 
     dates.enddate::DATE - months.startdate::DATE + 1, -- takes care of last month 
     months.enddate::DATE - months.startdate::DATE + 1 -- takes care of full months from the middle of the intervals 
    ) AS "days" 
FROM dates 
-- get months as first day in that month 
CROSS JOIN LATERAL (
    SELECT * FROM generate_series(
     (to_char(dates.startdate, 'YYYY-MM-') || '01')::DATE, 
     (to_char(dates.enddate + INTERVAL '1 month', 'YYYY-MM-') || '01')::DATE - 1, INTERVAL '1 month') m 
) days 
-- get months as start date and end date 
CROSS JOIN LATERAL (
    SELECT 
     days.m::DATE AS startdate, 
     (days.m + INTERVAL '1 month')::DATE - 1 AS enddate 
) months 
+0

這應該工作.. – dhS

+1

我添加了「快」的版本,以防萬一 – AlexanderMP

2

在這種特殊情況下,PLPGSQL功能可以提供比一個更好的性能純sql查詢。

create or replace function get_months(startdate date, enddate date) 
returns table (mon text, year int, days int) 
language plpgsql as $$ 
declare d date; 
begin 
    d:= date_trunc('month', startdate); 
    while d < enddate loop 
     mon:= to_char(d, 'Mon'); 
     year:= to_char(d, 'YYYY'); 
     days:= case 
      when d+ '1month'::interval > enddate then enddate- d+ 1 
      when d < startdate then (d+ '1month'::interval)::date- startdate 
      else (d+ '1month'::interval)::date- d 
     end; 
     return next; 
     d:= d+ '1month'::interval; 
    end loop; 
end 
$$; 

測試:

with my_table(startdate, enddate) as (
    values 
    ('2015-12-27 22:30', '2016-01-03 19:30'), 
    ('2016-01-01 12:45', '2016-02-09 18:30') 
) 

select * 
from my_table, 
lateral get_months(startdate::date, enddate::date) 

    startdate  |  enddate  | mon | year | days 
------------------+------------------+-----+------+------ 
2015-12-27 22:30 | 2016-01-03 19:30 | Dec | 2015 | 5 
2015-12-27 22:30 | 2016-01-03 19:30 | Jan | 2016 | 3 
2016-01-01 12:45 | 2016-02-09 18:30 | Jan | 2016 | 31 
2016-01-01 12:45 | 2016-02-09 18:30 | Feb | 2016 | 9 
(4 rows) 
相關問題