PL/SQL (How to calculate the first and last day of any quarter of any year)

巧了我就是萌 提交于 2019-12-11 19:44:06

问题


I have one table, per_all_peopl_f, with following columns:

name  person_id  emp_flag  effective_start_date   effective_end_date   DOJ
    --------------------------------------------------------------------------------    
    ABC   123          Y       30-MAR-2011              30-MAR-2013       10-FEB-2011
    ABC   123          Y       24-FEB-2011              27-FEB-2011       10-FEB-2011
    DEF   345          N       10-APR-2012              30-DEC-4712       15-SEP-2011

There are many entries (1000+) with repeated data and different effective start dates.

I have to calculate the Workforce headcount. That is, the number of employees that exits the company quarterly.

The following columns have to be fetched:

  • Headcount in 2012 (1st quarter)
  • Headcount in 2013 (1st quarter)
  • difference between the two headcounts
  • % difference

This has to be done quarterly. that is whichever quarter I pass the workforce headcount should be calculated according to that.

The query I have written is

CREATE OR REPLACE FUNCTION function_name
  (l_end_date ,l_start_date  ) 
  RETURN number;
  IS 
    l_emp

  BEGIN
    select count(distinct papf.person_id)
      into l_emp
      from per_all_people_f papf
     where papf.emp_flag ='Y'
       and effective_start_date >=l_end_date
       and effective_end_date <=l_start_date ;

    return l_emp; 
END function_name;


create xx_pack_name  body
is 
crate or replace procedure proc_name( l_quarter number,
                      p_person_id number,
                      l_year number )
    cursor cur_var
    is 
       select function_name(l_start_date ,l_end_date ) EMP_2012,
              function_name(l_start_date1,l_end_date1 ) EMP_2013,
              function_name(l_start_date ,l_end_date )-function_name(l_start_date1,l_end_date1 ) Diff
         from dual;


Begin
if(l_year=2012)

if l_quarter =1
then
l_start_date :='01-Jan-2013';
l_end_date :='31-APR-2013';

elsif l_quarter =2
then
l_start_date :='01-May-2013';
l_end_date :='31-Aug-2013';

else
l_start_date :='01-Sep-2013';
l_end_date :='31-Dec-2013';

end if;
end if;
if(l_year=2013)

then 

if l_quarter =1
then
l_start_date :='01-Jan-2013';
l_end_date :='31-APR-2013';

elsif l_quarter =2
then
l_start_date :='01-May-2013';
l_end_date :='31-Aug-2013';

else
l_start_date :='01-Sep-2013';
l_end_date :='31-Dec-2013';

end if;
end if;

for cur_val in cur_var 
loop
dbms_output.put_line(cur_var.emp_2012 || cur_var.emp_2013 ||cur_var.diff )

end loop



end xx_pack_name  ;

This package is taking too long.

Is there any other way I can calculate the last and first day of quarter of any year ????

And also when I am calculating the

percentage function_name(l_start_date ,l_end_date )-function_name(l_start_date1,l_end_date1 ) /100

the output is not coming in the select statement


回答1:


I find this question very confusing. If the real question is how to calculate the quarter of an arbitrary DATE then there's already plenty of examples, like:

  • Oracle - break dates into quarters
  • Find First and Last Day of the last Quarter in ORACLE

How to calculate the quarter of an arbitrary date

Some dates for testing:

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

Find the quarters:

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;

Results:

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
...

A PL/SQL procedure that returns the first and last days of a quarter

The quarter's start and end dates are constant for all years except the year part. I.e. the second quarter always begins on 1st April and end on 30th June on every year. Thus the day and month can be fixed and only year part have to be adjusted.

A function can only return one value so the subroutine is implemented as procedure instead. I also provided a function wrappers to the procedure:

-- 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

How to use the subroutines above:

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;
/


来源:https://stackoverflow.com/questions/18549406/pl-sql-how-to-calculate-the-first-and-last-day-of-any-quarter-of-any-year

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!