web-dev-qa-db-fra.com

Date de fin générique du trimestre, PostgreSQL

J'aimerais produire la date de fin générique du trimestre pendant une date donnée.

Ex: Si j'ai 2010-01-01, J'aimerais revenir 2010-03-31, etc.

Je peux obtenir le quart de numéro et année:

select to_char(date_trunc('quarter',  current_date)::date, 'yyyy-q');

Qui retourne 2017-3 Depuis aujourd'hui est 2017-07-14

Comment puis-je obtenir la date de fin du quart?

Je peux avoir la réponse, mais c'est très moche:

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 

Qui retourne 2015-03-31 Depuis que j'ai mis en 2015-01-01.

Y a-t-il une meilleure façon?

4
mountainclimber

Je pense que le moyen le plus court et le plus élégant de résoudre ce problème est d'utiliser date_trunc('quarter',d) (qui sera Récupérez le Démarrer du trimestre) + 3 mois - 1 jour et utilisez l'expression pour créer un 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 ;

... et ensuite l'utiliser:

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 ;
 D | fin_of_quartter [.____]: --------- : -------------- 
 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 

Vous pouvez le vérifier sur dbfiddle --- (ici


Vous pouvez également raccourcir un peu votre approche originale en utilisant le simple version de 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) ;

Vous pouvez le vérifier sur dbfiddle ici


Si vous avez besoin de le faire très souvent, définissez une fonction:

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 ;

dbfiddle ICI

11
joanolo