I have the following requirements.
I want to fetch the job schedules of the staffs for particular day(current day) and particular store (e.g. 12). Also, there is scenario that other store (13) staffs will come and work for store (12) and store 12 staffs can work for other stores.
Status table is storing the present/Absent details if staffs mark their attendance.
I want to fetch 1) the schedules of the staffs for the store 12 from staffschedules regardless of staffstatus has entry or not on the particular day.
2) the schedules from staffschedules who are all from other stores and reject the schedules of the staffs who went to other stores by referring the staffstatus (if entry is in status table, i need to retrieve, else nothing)
2 Tables:
- Schedules
- Status ----> staffs present/absent details
I have written the below query. It takes average of 30 seconds to run. In worst cases, 93 seconds.
STAFFSCHEUDLES TABLE SCHEMA:
CREATE TABLE "STAFFSCHEDULES"
(
"STORE_ID" VARCHAR2(75 BYTE) NOT NULL ENABLE,
"START_DATE" DATE NOT NULL ENABLE,
"JOB_ID" VARCHAR2(22 BYTE) NOT NULL ENABLE,
"START_TIME" VARCHAR2(5 BYTE) NOT NULL ENABLE,
"END_DATE" DATE NOT NULL ENABLE,
"END_TIME" VARCHAR2(5 BYTE) NOT NULL ENABLE,
"JOBNAME" VARCHAR2(1500 BYTE)
CONSTRAINT "PK_STAFFSCHEDULES" PRIMARY KEY ("STORE_ID", "START_DATE", "JOB_ID", "START_TIME")
CREATE UNIQUE INDEX "PK_STAFFSCHEDULES" ON "STAFFSCHEDULES"
(
"STORE_ID", "START_DATE", "JOB_ID", "START_TIME"
)
CREATE INDEX "IDX1_STAFFSCHEDULES_STORSTDT" ON "STAFFSCHEDULES"
(
"STORE_ID",
"START_DATE"
)
CREATE INDEX "STAFFSCHEDULES_IDX" ON "STAFFSCHEDULES"
(
"JOB_ID"
)
STAFFSTATUS TABLE SCHEMA:
CREATE TABLE "STAFFSTATUS"
(
"JOB_SEQ_ID" NUMBER(10,0) NOT NULL ENABLE,
"JOB_ID" VARCHAR2(15 BYTE) NOT NULL ENABLE,
"STORE_ID" VARCHAR2(4 BYTE) NOT NULL ENABLE,
"JOB_DATE" DATE NOT NULL ENABLE,
"STATUS" VARCHAR2(1 BYTE) DEFAULT 'N' ,
"SERVER_DATE" DATE
CONSTRAINT "PK_STAFFSTATUS" PRIMARY KEY ("JOB_SEQ_ID")
CONSTRAINT "UK_STAFFSTATUS" UNIQUE ("JOB_ID", "STORE_ID", "JOB_DATE")
)
CREATE INDEX "INDEX_STAFFSTATUS" ON "STAFFSTATUS"
(
"STORE_ID",
"STATUS"
)
CREATE INDEX "INDEX_STAFFSTATUS_JOB_DT" ON "STAFFSTATUS"
(
"STORE_ID",
"JOB_DATE",
"STATUS"
)
CREATE UNIQUE INDEX "PK_STAFFSTATUS" ON "STAFFSTATUS"
(
"JOB_SEQ_ID"
)
CREATE UNIQUE INDEX "UK_STAFFSTATUS" ON "STAFFSTATUS"
(
"JOB_ID", "STORE_ID", "JOB_DATE"
)
CREATE INDEX "INDEX_STAFFSTATUS_UPDT" ON "STAFFSTATUS"
(
"STORE_ID",
"SERVER_DATE"
)
QUERY TO RETRIEVE THE SCHEDULES:
SELECT *
From StaffSchedules
WHERE store_id='15'
AND ((start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
AND TO_CHAR(start_date,'HH24:MI') <= start_time)
OR((end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
AND TO_CHAR(end_date,'HH24:MI') >= end_time))
AND job_id NOT IN
(SELECT distinct s2.job_id
FROM staffschedules s2
WHERE s2.store_id=store_id
AND ((s2.start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
AND TO_CHAR(s2.start_date,'HH24:MI') <= s2.start_time)
OR((s2.end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
AND TO_CHAR(s2.end_date,'HH24:MI') >= s2.end_time))
AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) = 'NOTALLOCATED')
AND job_id NOT IN (
Select job_Id From staffStatus Where Trunc(job_Date)=Trunc(to_date('07/08/2013','MM/DD/YYYY')) And Store_Id!='15')
UNION ALL
SELECT *
From StaffSchedules ss
Right Outer Join staffStatus status On Es.job_Id=status.job_Id And status.Store_Id<>ss.Store_Id And
(Trunc(status.job_Date)=Trunc(ss.Start_Date) Or Trunc(status.job_Date)=Trunc(ss.End_Date))
AND ((start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
AND TO_CHAR(start_date,'HH24:MI') <= start_time)
OR((end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
AND TO_CHAR(end_date,'HH24:MI') >= end_time))
AND job_id NOT IN
(SELECT distinct s2.job_id
FROM staffschedules s2
WHERE s2.store_id=store_id
AND ((s2.start_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY')) AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+(1-1/24/60/60)
AND TO_CHAR(s2.start_date,'HH24:MI') <= s2.start_time)
OR((s2.end_date BETWEEN TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1/24/60/60 AND TRUNC(to_date('07/08/2013','MM/DD/YYYY'))+1)
AND TO_CHAR(s2.end_date,'HH24:MI') >= s2.end_time))
AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) = 'NOTALLOCATED')
AND status.store_id='15' AND TRUNC(status.job_date)=TRUNC(to_date('07/08/2013','MM/DD/YYYY'))
ORDER BY job_id,start_date,start_time;
EXECUTION PLAN:
----------------------------------------------------------------------------------------------------- -------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------- -------------
| 0 | SELECT STATEMENT | | 41 | 10865 | 37990 (1)| 00:07:36 |
| 1 | SORT ORDER BY | | 41 | 10865 | 37989 (67)| 00:07:36 |
| 2 | UNION-ALL | | | | | |
| 3 | NESTED LOOPS ANTI | | 1 | 265 | 12649 (1)| 00:02:32 |
| 4 | NESTED LOOPS ANTI | | 1 | 146 | 12620 (1)| 00:02:32 |
|* 5 | TABLE ACCESS BY INDEX ROWID| STAFFSCHEDULES | 109 | 13734 | 12401 (1)| 00:02:29 |
|* 6 | INDEX RANGE SCAN | IDX1_STAFFSCHEDULES_STORSTDT | 65068 | | 410 (1)| 00:00:05 |
|* 7 | INDEX RANGE SCAN | UK_STAFFSTATUS | 137K| 2694K| 2 (0)| 00:00:01 |
|* 8 | TABLE ACCESS BY INDEX ROWID | STAFFSCHEDULES | 1 | 119 | 29 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | STAFFSCHEDULES_IDX | 83 | | 2 (0)| 00:00:01 |
| 10 | NESTED LOOPS ANTI | | 40 | 10600 | 25340 (1)| 00:05:05 |
| 11 | NESTED LOOPS | | 40 | 5840 | 24820 (1)| 00:04:58 |
| 12 | TABLE ACCESS BY INDEX ROWID| STAFFSTATUS | 2208 | 44160 | 2931 (1)| 00:00:36 |
|* 13 | INDEX RANGE SCAN | INDEX_STAFFSTATUS_SCHD_DT | 2208 | | 1525 (1)| 00:00:19 |
|* 14 | TABLE ACCESS BY INDEX ROWID| STAFFSCHEDULES | 1 | 126 | 29 (0)| 00:00:01 |
|* 15 | INDEX RANGE SCAN | STAFFSCHEDULES_IDX | 83 | | 2 (0)| 00:00:01 |
|* 16 | TABLE ACCESS BY INDEX ROWID | STAFFSCHEDULES | 1 | 119 | 13 (0)| 00:00:01 |
|* 17 | INDEX RANGE SCAN | PK_STAFFSCHEDULES | 1 | | 12 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------- -------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - filter(("START_DATE"<=TO_DATE(' 2013-07-08 23:59:59', 'syyyy-mm-dd hh24:mi:ss') AND
"START_DATE">=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"START_TIME">=TO_CHAR(INTERNAL_FUNCTION(START_DATE"),'HH24:MI') OR
"END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND
"END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("END_DATE"),'HH24:MI')))
6 - access("STORE_ID"='15')
7 - access("JOB_ID"="JOB_ID")
filter(TRUNC(INTERNAL_FUNCTION("JOB_DATE"))=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "STORE_ID"<>'15')
8 - filter("S2"."STORE_ID"='15' AND ("S2"."START_DATE"<=TO_DATE(' 2013-07-08 23:59:59',
'syyyy-mm-dd hh24:mi:ss') AND "S2"."START_DATE">=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "S2"."START_TIME">=TO_CHAR(INTERNAL_FUNCTION("S2"."START_DATE"),'HH24:MI'
) OR "S2"."END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"S2"."END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND
"S2"."END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("S2"."END_DATE"),'HH24:MI')) AND
SUBSTR("S2"."JOBNAME",INSTR("S2"."JOBNAME",'/',1,7)+1,8)='NOTALLOCATED')
9 - access("JOB_ID"="S2"."JOB_ID")
13 - access("STATUS"."STORE_ID"='15')
filter(TRUNC(INTERNAL_FUNCTION("STATUS"."JOB_DATE"))=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd
hh24:mi:ss'))
14 - filter(("START_DATE"<=TO_DATE(' 2013-07-08 23:59:59', 'syyyy-mm-dd hh24:mi:ss') AND
"START_DATE">=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"START_TIME">=TO_CHAR(INTERNAL_FUNCTION("START_DATE"),'HH24:MI') OR
"END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND
"END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("END_DATE"),'HH24:MI')) AND
"STATUS"."STORE_ID"<>"STORE_ID" AND (TRUNC(INTERNAL_FUNCTION("STATUS"."JOB_DATE"))=TRUNC(INTERNAL_FUNCT
ION("START_DATE")) OR TRUNC(INTERNAL_FUNCTION("STATUS"."JOB_DATE"))=TRUNC(INTERNAL_FUNCTION("
END_DATE"))) AND "STORE_ID"<>'15')
15 - access("STATUS"."JOB_ID"="JOB_ID")
16 - filter(("S2"."STORE_ID"='15' AND ("S2"."START_DATE"<=TO_DATE(' 2013-07-08 23:59:59',
'syyyy-mm-dd hh24:mi:ss') AND "S2"."START_DATE">=TO_DATE(' 2013-07-08 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "S2"."START_TIME">=TO_CHAR(INTERNAL_FUNCTION("S2"."START_DATE"),'HH24:MI'
) OR "S2"."END_DATE"<=TO_DATE(' 2013-07-09 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"S2"."END_DATE">=TO_DATE(' 2013-07-08 00:00:01', 'syyyy-mm-dd hh24:mi:ss') AND
"S2"."END_TIME"<=TO_CHAR(INTERNAL_FUNCTION("S2"."END_DATE"),'HH24:MI')) AND
SUBSTR("S2"."JOBNAME",INSTR("S2"."JOBNAME",'/',1,7)+1,8)='NOTALLOCATED')
17 - access("S2"."STORE_ID"="STORE_ID" AND "JOB_ID"="S2"."JOB_ID")
filter("JOB_ID"="S2"."JOB_ID" AND "S2"."STORE_ID"<>'15')
Sample Staffschedule data:
storeid job_id startdate starttime enddate endtime jobname
12 1 2013-07-11 09:00:00 09:00 2013-07-11 18:00:00 10:00 class A
12 1 2013-07-11 09:00:00 10:00 2013-07-11 18:00:00 11:00 class B
12 1 2013-07-11 09:00:00 11:00 2013-07-11 18:00:00 18:00 class C
Please help me in this issue.
Thanks in advance
storein both the tables? Will staff that are originally instore 12also be present in staffstatus?