2013-07-06 120 views
2

我有以下要求。Oracle sql查询需要优化

我想获取特定日期(当天)和特定商店(如12)的员工的工作时间表。此外,还有其他店铺(13)员工来店工作(12),店铺12员工可以为其他店铺工作的场景。

状态表存储了当前/缺席的详细信息,如果员工标记出席。

我想取 1)员工日程安排员工日程安排,无论员工状况如何,员工日程安排都不在特定日期。

2)从staffschedules谁都是从其他商店,并拒绝谁,通过参考staffstatus去其他商店的职员安排时间表(如果条目是在状态表,我需要找回,否则无)

2表:

  1. 时刻表
  2. 状态---->人员存在/不存在的信息

我已经写了下面查询。平均需要30秒才能运行。在最坏的情况下,93秒。

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

查询,以获得时间表:

  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;     

执行计划:

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

样品Staffschedule数据:

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 

请帮我在这个问题上。

在此先感谢

+0

这两张表的表结构是什么?为什么你需要在两个表中存储?员工是否会出现在员工状态中? – RedBaron

+2

请显示解释计划输出,以及存在哪些索引等。我们不介意读者。 – OldProgrammer

+0

解释计划已更新。请看看并分享你的观点。 – user2556379

回答

0

你的主过滤器是date。所以你会希望按日期进行索引。但是,如果日期的记录数远远少于表中的记录数,这只会有意义。说< 5%。因此,你的第一个好消息将是staffschedules.date(或其他一些以日期开始的多部分索引)的索引。

您应该在sqlplus中使用示例日期分别运行这两个查询,并查看时间花在哪里。如果时间花在第一个查询上,那么这将是date索引或甚至date-store索引。这部分不应该慢。

如果UNION的第二部分是缓慢的,打破分为两个部分,调查每个:

SELECT * 
    FROM staffschedules 
    WHERE date = v_date 
    AND store <> v_store 

SELECT staffid 
    FROM staffstatus 
    WHERE store=v_store 
    AND jobdate=v_date 

如果第一部分是缓慢的,再次,日期索引。如果第二个缓慢,那么它可能需要staffstatus.jobdate上的索引。如果每个运行速度相当快,那么您必须查看staffid如何加入,但它很可能是jobdate上的索引情况。

+0

联盟的第二部分需要时间。我更新了解释计划和表格架构。请看一看。根据我的理解,第二部分是按照员工时间表中的选择,员工状态中的选择和表格连接执行的。所以需要时间。有没有什么方法可以先加入然后选择。我的意思是加入行,然后选择staffschedules? – user2556379

1

好的,问题数据有很大的变化,所以让我们从头开始研究它。

首先,在查询文本存在一个未件事:

AND SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) = 'NOTALLOCATED') 

没有与查询别名ses2没有表,所以我不知道如何处理的东西做的想法。请注意,它从不计算为true,因为length('NOTALLOCATED')多于8.因此,该条件从答案中删除。

影响查询性能的主要因素是过度使用NOT IN条件。在大多数情况下,这种情况必须更改为主查询中针对字段的简单测试。
在从问题解决问题,我们有类似的情况是:

select 
    t.* 
from 
    my_table t 
where 
    <big-basket-of-conditions-here> 
    and 
    t.field_1 not in (select t.field_1 
        from my_table t 
        where 
         <same-big-basket-of-conditions>  
         and 
         <one_more_test> 
        ) 

这必须改变,以

select 
    t.* 
from 
    my_table t 
where 
    <big-basket-of-conditions-here> 
    and 
    not (<one-more-test>) 

例如您有:

  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 SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,8) <> 'NOTALLOCATED') 

无子查询和NOT IN
如果需要加入其他表来进行测试,好做它的主要选择:做外连接,然后测试场:

select * from (
    select 
    ss.*, 
    nvl(SUBSTR(ses2.org_path,INSTR(ses2.org_path,'/',1,7)+1,12),'X') alloc_flag 
    from 
    staffschedules ss, 
    some_table  ses2 
    where 
    ses2.some_field (+) = ss.some_field and ... 
) 
where alloc_flag <> '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' 
)   

它包含两件坏事。其中之一在上面讨论过,接下来是在条件下使用!=。这样的条件消除了有效索引使用的任何可能性。而这种情况最糟糕的情况是,所有索引都首先有store_id,所以数据库引擎必须遍历整个索引才能找到所有条件,并且不能倒退到另一个索引job_date
所以,这一条件可以用同样的技术

select * from (
    select 
    ss.*, 
    nvl(statuses.store_id,'X') status_store_id 
    from 
    staffschedules ss, 
    staffstatus statuses 
    where 
    statuses.job_id (+) = ss.some_field 
    Trunc(job_Date (+)) = Trunc(to_date('07/08/2013','MM/DD/YYYY')) 
    and ... 
) 
where status_store_id = '15' 

也是唯一被rewrited是场功能的使用,同时加入。 Trunc(job_date)看起来很直观可能是,但性能不好,因为在这种情况下数据库不能使用job_date上的索引。所以在这种情况下更好的使用边界条件:

job_Date >= to_date('07/08/2013','MM/DD/YYYY') 
    and 
    job_Date < to_date('07/08/2013','MM/DD/YYYY') + 1 

最后,我写的例子查询得到完整的时间表列表。你可以在this SQLFiddle或下面看看它。 它为指定的商店和日期返回完整的一组日程和状态。
因为我不确定有关理解调度逻辑,您可以自行筛选查询结果。

with params as (
    -- Just to write parameters only once. 
    -- Note that parameter date truncated. 
    select 
    trunc(to_date('07/24/2013 07:20','MM/DD/YYYY HH24:MI')) as date_val, 
    '15'             as store_id 
    from dual 
), 
store_jobs_from_schedule as ( 
    -- Select all valid schedules on desired date for specified store with corresponding statuses if any. 
    select       
    scheduled_jobs.job_id   job_id, 
    scheduled_jobs.store_id   schedule_store_id, 
    scheduled_jobs.start_date  schedule_start_date, 
    scheduled_jobs.start_date_time schedule_start_time, 
    scheduled_jobs.end_date   schedule_end_date, 
    scheduled_jobs.end_date_time  schedule_end_time, 
    scheduled_jobs.jobname   schedule_job_name, 
    status_list.job_seq_id   status_id,  
    status_list.store_id    status_store_id, 
    status_list.job_date    status_job_date, 
    status_list.status    status 
    from 
    (       
     select -- get all schedules for specified date and store. 
     p.date_val, 
     schedules.job_id, 
     schedules.store_id, 
     schedules.start_date, 
     (-- Calculate exact start time as date and time value 
      trunc(schedules.start_date) + 
      (to_date(schedules.start_time,'hh24:mi') - to_date('00:00','hh24:mi')) 
     ) start_date_time, 
     schedules.end_date, 
     (-- Calculate exact end time as date and time value 
      trunc(schedules.end_date) + 
      (to_date(schedules.end_time,'hh24:mi') - to_date('00:00','hh24:mi')) 
     ) end_date_time, 
     schedules.jobname 
     from 
     params   p, 
     staffschedules schedules 
     where         
     -- scheduled to specified store 
     schedules.store_id = p.store_id 
     and          
     -- start before the end of desired date 
     schedules.start_date < p.date_val + 1 
     and        
     -- end after beginning of desired date 
     schedules.end_date >= p.date_val 
    ) 
       scheduled_jobs, 
    staffstatus status_list 
    where               
    -- Check if schedule start time are valid 
    (scheduled_jobs.start_date <= scheduled_jobs.start_date_time) 
    and 
    -- Check if schedule end time are valid 
    (scheduled_jobs.end_date >= scheduled_jobs.end_date_time) 
    and       
    -- Link status by staff and date if any - only on desired date, 
    -- not for full schedule length 
    status_list.job_id (+) = scheduled_jobs.job_id 
    and 
    status_list.job_date (+) >= scheduled_jobs.date_val 
    and 
    status_list.job_date (+) < scheduled_jobs.date_val + 1 
), 
store_stuff_jobs as (
    -- Select all statuses for specified date and store and link it to corresponding schedules if any 
    select -- clear data in invalid schedules 
    job_id                 job_id,  
    decode(is_valid_schedule,'N', null,    schedule_store_id) schedule_store_id, 
    decode(is_valid_schedule,'N', cast(null as date), schedule_start_date) schedule_start_date, 
    decode(is_valid_schedule,'N', cast(null as date), schedule_start_time) schedule_start_time, 
    decode(is_valid_schedule,'N', cast(null as date), schedule_end_date) schedule_end_date, 
    decode(is_valid_schedule,'N', cast(null as date), schedule_end_time) schedule_end_time, 
    decode(is_valid_schedule,'N', null,    schedule_job_name) schedule_job_name, 
    status_id                status_id,  
    status_store_id               status_store_id, 
    status_job_date               status_job_date, 
    status                 status 
    from ( 
    select -- Calculate if selected schedule are valid    
     job_id, 
     schedule_store_id, 
     schedule_start_date, 
     schedule_start_time, 
     schedule_end_date, 
     schedule_end_time, 
     schedule_job_name, 
     status_id,  
     status_store_id, 
     status_job_date, 
     status, 
     (-- Calculate flag to check if times of schedules are valid 
     case 
      when 
      (schedule_start_date > schedule_start_time) 
      or 
      (schedule_end_date < schedule_end_time) 
      then 'N' 
      else 'Y' 
     end   
    ) is_valid_schedule 
    from (
     select 
     status_list.job_id   job_id, 
     schedules.store_id   schedule_store_id, 
     schedules.start_date  schedule_start_date, 
     (-- Calculate exact start time as date and time value 
      trunc(schedules.start_date) + 
      (to_date(schedules.start_time,'hh24:mi') - to_date('00:00','hh24:mi')) 
     )       schedule_start_time, 
     schedules.end_date   schedule_end_date, 
     (-- Calculate exact end time as date and time value 
      trunc(schedules.end_date) + 
      (to_date(schedules.end_time,'hh24:mi') - to_date('00:00','hh24:mi')) 
     )       schedule_end_time, 
     schedules.jobname   schedule_job_name, 
     status_list.job_seq_id  status_id,  
     status_list.store_id  status_store_id, 
     status_list.job_date  status_job_date, 
     status_list.status   status 
     from 
     params   p, 
     staffstatus status_list, 
     staffschedules schedules 
     where 
     status_list.job_date >= p.date_val  
     and 
     status_list.job_date < p.date_val + 1  
     and 
     status_list.store_id = p.store_id 
     and          
     -- Link schedules for same staff on same date if any. 
     -- Even schedules to same store, because we need exactly same 
     -- record as in first query to eliminate duplicates on last step. 
     schedules.job_id (+) = status_list.job_id 
     and 
     schedules.start_date (+) < trunc(status_list.job_date) + 1 -- start before the end of desired date 
     and 
     schedules.end_date (+) >= trunc(status_list.job_date) -- end after beginning of desired date 
    ) 
) 
) 
    select 
    -- records comes from schedules 
    job_id, 
    schedule_store_id store_id, 
    schedule_store_id, 
    schedule_start_date, 
    schedule_start_time, 
    schedule_end_date, 
    schedule_end_time, 
    schedule_job_name, 
    status_id,  
    status_store_id, 
    status_job_date, 
    status 
    from 
    store_jobs_from_schedule 
union -- duplicates eliminated 
    select 
    -- records comes from status 
    job_id, 
    status_store_id store_id, 
    schedule_store_id, 
    schedule_start_date, 
    schedule_start_time, 
    schedule_end_date, 
    schedule_end_time, 
    schedule_job_name, 
    status_id,  
    status_store_id, 
    status_job_date, 
    status 
    from 
    store_stuff_jobs 
order by 
    job_id, schedule_start_date, schedule_start_time 
+0

谢谢ThinkJet。这工作正常。但它不会返回此场景的时间表。员工xyz的家庭商店是13.今天他在商店工作12.在staffstatus表中,xyz商店是12(主机商店,所以出勤率在商店12中标记)和staffschedules表xyz商店是13(时间表总是与家庭商店id一起) 。如果我想要取得店铺12的时间表,外部条件拒绝店铺ID为13的时间表。有没有需要使用此查询获取不同的商店时间表? – user2556379

+0

@ user2556379与第一个问题版本相比,您已经更改了架构。什么字段对应于上一个问题的'staffid'?为什么你将日期和时间分成2个独立的列?为什么时间以字符格式存储?像TO_CHAR(start_date,'HH24:MI')<= start_time)'这样的比较对象的目的是什么? – ThinkJet

+0

对不起。 Staffid由Job_Id取代。样本数据在staffschedules中。 – user2556379