Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

PL/SQL (Como calcular o primeiro e o último dia de qualquer trimestre de qualquer ano)


Acho essa pergunta muito confusa. Se a verdadeira questão é como calcular o quarto de uma DATE arbitrária então já há muitos exemplos, como:

Como calcular o trimestre de uma data arbitrária

Algumas datas para testes:
create table lots_of_dates as
select trunc(sysdate - level * 7) as d
from dual
connect by level <= 52;

Encontre os trimestres:
select d,
       to_char(d, 'YYYY-Q') as QUARTER,
       trunc(d, 'Q') as Q_FIRST_DAY,
       add_months(trunc(d, 'Q'), 3) - 1 as Q_LAST_DAY
from lots_of_dates
order by 1;

Resultados:
D                  QUARTE Q_FIRST_DAY        Q_LAST_DAY
------------------ ------ ------------------ ------------------
02-SEP-12          2012-3 01-JUL-12          30-SEP-12
09-SEP-12          2012-3 01-JUL-12          30-SEP-12
16-SEP-12          2012-3 01-JUL-12          30-SEP-12
23-SEP-12          2012-3 01-JUL-12          30-SEP-12
30-SEP-12          2012-3 01-JUL-12          30-SEP-12
07-OCT-12          2012-4 01-OCT-12          31-DEC-12
14-OCT-12          2012-4 01-OCT-12          31-DEC-12
21-OCT-12          2012-4 01-OCT-12          31-DEC-12
28-OCT-12          2012-4 01-OCT-12          31-DEC-12
04-NOV-12          2012-4 01-OCT-12          31-DEC-12
11-NOV-12          2012-4 01-OCT-12          31-DEC-12
...

Um procedimento PL/SQL que retorna o primeiro e o último dia de um trimestre

As datas de início e término do trimestre são constantes para todos os anos, exceto a parte do ano. Ou seja o segundo trimestre sempre começa em 1º de abril e termina em 30 de junho de cada ano. Assim, o dia e o mês podem ser fixados e apenas a parte do ano deve ser ajustada.

Uma função pode retornar apenas um valor, então a sub-rotina é implementada como procedimento. Também forneci wrappers de função para o procedimento:
-- raises CASE_NOT_FOUND for non-existing quarters
create or replace procedure get_quarter_days(
  p_year in number,
  p_quarter in number,
  p_first_day out date,
  p_last_day out date
) deterministic as
begin
  case p_quarter
    when 1 then
      p_first_day := to_date(p_year || '-01-01', 'YYYY-MM-DD');
      p_last_day  := to_date(p_year || '-03-31', 'YYYY-MM-DD');
    when 2 then
      p_first_day := to_date(p_year || '-04-01', 'YYYY-MM-DD');
      p_last_day  := to_date(p_year || '-06-30', 'YYYY-MM-DD');
    when 3 then
      p_first_day := to_date(p_year || '-07-01', 'YYYY-MM-DD');
      p_last_day  := to_date(p_year || '-09-30', 'YYYY-MM-DD');
    when 4 then
      p_first_day := to_date(p_year || '-10-01', 'YYYY-MM-DD');
      p_last_day  := to_date(p_year || '-12-31', 'YYYY-MM-DD');
  end case;
end;
/
show errors

create or replace function get_quarter_first_day(
  p_year in number,
  p_quarter in number
) return date deterministic as
  v_first_day date;
  v_last_day date;
begin
  get_quarter_days(p_year, p_quarter, v_first_day, v_last_day);
  return v_first_day;
end;
/
show errors

create or replace function get_quarter_last_day(
  p_year in number,
  p_quarter in number
) return date deterministic as
  v_first_day date;
  v_last_day date;
begin
  get_quarter_days(p_year, p_quarter, v_first_day, v_last_day);
  return v_last_day;
end;
/
show errors

Como usar as sub-rotinas acima:
declare
  v_first_day date;
  v_last_day date;
begin
  get_quarter_days(2011, 1, v_first_day, v_last_day);
  dbms_output.put_line(v_first_day || ' - ' || v_last_day);
  get_quarter_days(2012, 2, v_first_day, v_last_day);
  dbms_output.put_line(v_first_day || ' - ' || v_last_day);
  get_quarter_days(2013, 3, v_first_day, v_last_day);
  dbms_output.put_line(v_first_day || ' - ' || v_last_day);
  get_quarter_days(2014, 4, v_first_day, v_last_day);
  dbms_output.put_line(v_first_day || ' - ' || v_last_day);

  dbms_output.put_line(get_quarter_first_day(2015, 1) || ' - ' ||
                       get_quarter_last_day(2015, 1));
end;
/