季度的通用结束日期,PostgreSQL

mou*_*r11 7 postgresql functions date interval

我想生成给定日期的通用季度结束日期。

例如:如果我有2010-01-01,我想返回2010-03-31,等等。

我可以得到季度号和年份:

select to_char(date_trunc('quarter',  current_date)::date, 'yyyy-q');
Run Code Online (Sandbox Code Playgroud)

2017-3从今天起返回的是2017-07-14

我如何很好地获得季度结束日期?

我可以得到答案,但它非常丑陋:

select to_char(date_trunc('year',  date '2015-01-01'),'yyyy') || '-' ||case
    when (select extract('quarter' from date_trunc('quarter', date '2015-01-01')::date )) = 1 then '03-31'
    when (select extract('quarter' from date_trunc('quarter', date '2015-01-01')::date )) = 2 then '06-30'
    when (select extract('quarter' from date_trunc('quarter', date '2015-01-01')::date )) = 3 then '09-30'
    when (select extract('quarter' from date_trunc('quarter', date '2015-01-01')::date )) = 4 then '12-31'
    else '?'
    end 
Run Code Online (Sandbox Code Playgroud)

返回2015-03-31因为我把2015-01-01

有没有更好的办法?

joa*_*olo 13

我认为解决这个问题的最短和最优雅的方法是使用date_trunc('quarter',d)(将检索季度的开始+ 3 个月 - 1 天,并使用表达式创建一个FUNCTION

CREATE FUNCTION end_of_quarter (d date) 
RETURNS date AS
$$
SELECT
    CAST(date_trunc('quarter', d)  + interval '3 months' - interval '1 day' AS date)
$$
LANGUAGE SQL IMMUTABLE ;
Run Code Online (Sandbox Code Playgroud)

...然后使用它:

SELECT
    d, end_of_quarter(d)
FROM
    (SELECT 
        CAST(d0 AS date) AS d 
    FROM 
        generate_series(date '2017-01-01', date '2017-12-31', interval '6 days') AS s(d0)
    ) AS q ;
Run Code Online (Sandbox Code Playgroud)
d | 季末
:---------- | :-------------
2017-01-01 | 2017-03-31    
...
2017-03-26 | 2017-03-31    
2017-04-01 | 2017-06-30    
...
2017-06-18 | 2017-06-30    
2017-07-06 | 2017-09-30    
2017-07-12 | 2017-09-30    
...   
2017-09-22 | 2017-09-30    
2017-09-28 | 2017-09-30    
2017-10-04 | 2017-12-31    
2017-10-10 | 2017-12-31    
...  
2017-12-21 | 2017-12-31    
2017-12-27 | 2017-12-31    

您可以在此处的dbfiddle 中查看


您还可以通过使用以下简单版本来缩短您的原始方法CASE expression WHEN value THEN ...

SELECT
    d, 
    extract('year' from d) || '-' ||
    /* case expression when value instead of case when expression */
    case extract('quarter' from d)
        when 1 then '03-31'
        when 2 then '06-30'
        when 3 then '09-30'
        else        '12-31'
    end AS end_of_quarter
FROM
    generate_series(date '2017-01-01', date '2017-12-31', interval '6 days') AS s(d) ;
Run Code Online (Sandbox Code Playgroud)

您可以在此处的dbfiddle 中查看


如果您需要经常这样做,请定义一个函数:

CREATE FUNCTION end_of_quarter (d date) 
RETURNS date AS
$$
SELECT
    cast (extract('year' from d) || '-' ||
        case extract('quarter' from d)
            when 1 then '03-31'
            when 2 then '06-30'
            when 3 then '09-30'
            else        '12-31'
        end
    AS date)
$$
LANGUAGE SQL IMMUTABLE ;
Run Code Online (Sandbox Code Playgroud)

dbfiddle在这里