0

我有三张桌子:-

per_Absences_table 有 start_date、end_date。per_absence_type 有特权、休闲等 per_people_table 有员工编号、员工姓名

我想了解员工在两个日期之间申请的休假数。

例如:- 如果我将“1-JAN-2013”​​作为开始日期,“20-JUN-2013”​​作为结束日期,那么员工申请的所有休假都将作为输出

我已经为它编写了代码,当我传递任何参数时它都可以工作。但是假设有一名员工在 2013 年 5 月 10 日至 2013 年 5 月 20 日期间申请休假,并且我将开始日期设置为 2013 年 5 月 11 日,即 2013 年 5 月 11 日之后休假的员工应该来。

即应显示从 2013 年 5 月 10 日到 2013 年 5 月 20 日申请的休假。此外,如果我想找出申请休假到 2103 年 5 月 19 日的员工,甚至

那么这个假期应该会出现。所有其他案件都已处理完毕。

per_people_table :-

EMP_NUM     EMP_NAME 
P101        XYZ

PER_ABSENCE_TABLE

EMP_NUM  START_DATE    END_DATE       TYPE_ID
101      10-May-2013   15-May-2013    1

per_absence_type

type_id     leave_type
1            casual

现在,如果我将参数作为 2013 年 5 月 11 日(p_start_date)传递,那么这条记录应该会出现。

如果我将参数作为 2013 年 5 月 19 日(实际结束日期之前)传递,那么即使该记录也应该出现。

IE

declare

l_r varchar2(10) :=NULL;
L_E VARCHAR2(10) := NULL;
p_person_id VARCHAR2(10) :='P101',
                p_start_date VARCHAR2(10);
                p_end_date VARCHAR2(10);
                leave_type VARCHAR2(10);

BEGIN

Leave_detail_packa.Leave_detail_packA(NULL,NULL,'P101','11-MAY-2013',NULL,NULL);
END;

Leave_detail_packa body
procedure Leave_details( errbuff out varchar2,
            retcode out varchar2,
            p_person_id VARCHAR2,
            p_start_date varchar2,
            p_end_date varchar2,
            leave_type varchar2
            )
as 
l_st_date :=to_date(trunc(fnd_conc_date.string_to_date(p_start_date)));
l_end_date :=to_date(trunc(fnd_conc_date.string_to_date(p_end_date)));  

/****************Cursor for start date ****************************/
Cursor c_var_st_date
is select
to_char(paa.date_start,'DD-MON-RRRR') Start_date

from    per_Absences_table paa,
    per_absence_type paat

where ( nvl(l_st_date,paa.date_start) between paa.date_start and paa.date_end
    or paa.date_start >=  nvl(l_st_date,paa.date_start))

paa.type_id =paat.type_id
and paat.name = nvl(leave_type,paat.name);



/****************Cursor for end date ****************************/
Cursor c_var_nd_date
is select
to_char(paa.date_end,'DD-MON-RRRR') End_date

from    per_Absences_table paa,
    per_absence_type paat

where ( nvl(l_st_date,paa.date_end) between paa.date_start and paa.date_end
    or paa.date_end <=  nvl(l_st_date,paa.date_end))

paa.type_id =paat.type_id
and paat.name = nvl(leave_type,paat.name);


/********** Cursor to give all the leave details ***************/

Cursor c_var(l_start_date varchar2,
         l_end_date1 varchar2)

is 
select 
emp_number employee_number,
emp_name employee_name,
leave_type Leave_type,
to_char(paa.date_end,'DD-MON-RRRR') End_date,
to_char(paa.date_start,'DD-MON-RRRR') Start_date,
sum(No_of_days) Leave_days

from 
per_Absences_table paa,
    per_absence_type paat,
per_people_table

where 

paa.date_start>= ( nvl(l_start_date),to_char(paa.date_start,'DD-MON-RRRR'))
    and paa.date_end <= ( nvl(l_end_date1),to_char(paa.date_end,'DD-MON-RRRR'))
AND EMP_NUM=P_PERSON_ID;


/**** Begin looping******************************************************/

for ( c_var_number in c_var_st_date)
loop
    for ( c_var_number1 in c_var_nd_date)
loop
    for ( c_var_number3 in c_var(c_var_st_date.start_end,c_var_nd_date.end_date)
loop


    dbms.output_put.line( c_var_number3.end_date,c_var_number3.start_date);

end loop;
end loop;
end loop;
4

2 回答 2

2

首先,根本不需要使用 PL/SQL 来执行此操作。它可以在单个 SQL 语句中完成。

其次,您没有为您的表提供 DDL,因此我将假设它们将我们设置如下(也在SQL Fiddle中与其他情况):

create table per_people ( 
    emp_num number not null
  , emp_name varchar2(100) not null
  , constraint pk_per_people primary key (emp_num)
    );

create table per_absence_type ( 
    type_id number not null
  , leave_type varchar2(100) not null
  , constraint pk_absence_type primary key (type_id)
    );

create table per_absence (
    emp_num number not null
  , start_date date not null
  , end_date date not null
  , type_id number not null
  , constraint pk_per_abs primary key (emp_num, start_date)
  , constraint fk_per_abs_emp foreign key (emp_num)
               references per_people(emp_num)
  , constraint fk_per_abs_typ foreign key (type_id)
               references per_absence_type (type_id)
  , constraint chk_per_abs_dates check (start_date <= end_date )
    );

这些是我对这些表的最小限制。如果您缺少其中之一,我建议您添加它。

此查询将为您提供所有缺勤的所有表中的所有信息:

select pp.emp_num
     , pp.emp_name
     , pa.start_date
     , pa.end_date
     , pat.leave_type
  from per_people pp
  join per_absence pa
    on pp.emp_num = pa.emp_num
  join per_absence_type pat
    on pa.type_id = pat.type_id

您想查找将在两个日期之间休假的所有员工。为此,您需要在上述查询中添加 WHERE 子句。假设员工有以下缺勤:

insert all
 into per_absence values( 101, date '2013-05-10', date '2013-05-15', 1)
 into per_absence values( 101, date '2013-09-10', date '2013-09-10', 1)
 into per_absence values( 102, date '2013-05-15', date '2013-05-20', 1)
 into per_absence values( 103, date '2013-05-05', date '2013-05-20', 1)
select * from dual;

如果您传递了 2013-05-15 的开始日期和 2013-05-20 的结束日期,您会期望返回三行。如果您通过 2013-05-16 的开始日期,您只会期望两个。

你必须看看你想如何构造你的 WHERE 子句。查看您想要的日期,您的开始日期在缺勤开始日期和结束日期之间,或者您的结束日期在缺勤开始日期和结束日期之间。不要忘记缺勤只能是一天,因此您希望在比较中包括开始日期和结束日期。

这会将查询更改为:

select pp.emp_num
     , pp.emp_name
     , pa.start_date
     , pa.end_date
     , pat.leave_type
  from per_people pp
  join per_absence pa
    on pp.emp_num = pa.emp_num
  join per_absence_type pat
    on pa.type_id = pat.type_id
 where ( :start_date between pa.start_date and pa.end_date
         or :end_date between pa.start_date and pa.end_date
            )

现在,您要查找特定员工在给定日期之间的休假数。由于您的表已正确规范化,您只需 GROUP BY EMP_NUM 即可为每个员工获取它。

假设您希望在 2013-05-15 和 2013-05-20 之间对 EMP_NUM 1(单个员工,因此不需要 GROUP BY)进行此操作,查询将如下所示:

select count(*) as no_leaves
  from per_people pp
  join per_absence pa
    on pp.emp_num = pa.emp_num
  join per_absence_type pat
    on pa.type_id = pat.type_id
 where emp_num = 101
   and ( date '2013-05-15' between pa.start_date and pa.end_date
         or date '2013-05-20' between pa.start_date and pa.end_date
            )
于 2013-06-22T11:47:56.383 回答
0

如果我遇到这个问题,我会创建一个日历表,使用 JOIN BETWEEN paa.date_start AND paa.date_end; 这样,无论他们的休假何时开始或结束,我都知道他们是否在任何一天都休假。如果从那里您有兴趣了解他们休了多少假,将连续天数定义为休假的一个实例,那么您只需要找出休假天数之间的间隔即可。

于 2013-06-21T17:42:53.457 回答