Postgresql 研究生:计算过去X年的工作月数

Postgresql 研究生:计算过去X年的工作月数,postgresql,Postgresql,我有一个用户表和一个作业。用户有许多作业,作业有开始日期和结束日期: Column | Type | Modifiers ----------------+-----------------------------+--------------------------------------------------- id |

我有一个用户表和一个作业。用户有许多作业,作业有开始日期和结束日期:

     Column     |            Type             |                     Modifiers                     
----------------+-----------------------------+---------------------------------------------------
 id             | integer                     | not null default nextval('jobs_id_seq'::regclass)
 title          | character varying           | 
 employer       | character varying           | 
 start_date     | date                        | 
 end_date       | date                        | 
 user_id        | integer                     | 
我需要计算一个人在过去X年内工作的总月数

我已经看了一些重叠和间歇,但我不太清楚我需要什么。我想确保即使开始日期在X年范围之外,我仍然计算在该范围内的月份

以下是我到目前为止的情况:

选择sumEXTRACTYEAR FROM months*12+EXTRACTMONTH FROM months 作为工作月 从…起 选择当前案例 那么什么时候是真的 年龄当前日期,开始日期 其他日期结束日期、开始日期 以月份结束 从作业内部加入作业上的用户。用户\u id=users.id 其中users.id=4 随着时间的推移;
基本查询如下:

SELECT sum(extract(year from months) * 12 + extract(month from months)) AS working_months
FROM (
  SELECT
    age(CASE (start_date, start_date) OVERLAPS (current_date, interval '-5 years')
        WHEN true THEN start_date
        ELSE current_date - interval '5 years'
        END AS strt::timestamp,
        CASE current
        WHEN true THEN current_date
        ELSE end_date
        END AS fin::timestamp) AS months
  FROM jobs
  WHERE user_id = 4) AS employment_time;
您也可以将其放入一个SQL函数中,该函数的参数为年数和用户id。请注意,您会从单个作业中丢弃部分月份。您可以将extractday from months/30添加到顶部选择,以将部分月份收获为完整月份

这假设作业不能重叠。如果他们这样做了,那么查询就会变得更加复杂

with jobs (start_date, end_date, user_id) as ( values
    ('2000-01-01'::date, '2005-12-31'::date, 1),
    ('2007-10-01', '2008-09-30', 1),
    ('2010-09-01', '2014-10-20', 1)
)
select
    user_id,
    extract(year from work_time) * 12 + extract(month from work_time) as months
from (
    select
        user_id,
        sum(age(upper(period), lower(period))) as work_time
    from (
        select
            user_id,
            daterange(start_date, end_date, '[]') *
            daterange((current_date - interval '10 years')::date, current_date)
            as period
        from jobs
    ) s
    group by user_id
) s
;
 user_id | months 
---------+--------
       1 |     70
-

出于某种原因,Postgres对间隔'-X years'中的括号不满意,但当我删除它们时,它会在末尾吐出start::timestamp。@MikeWilliamson:我的错。Start是SQL保留字,间隔不需要括号。答案已更新。