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