如何查询差距以找出子表周期涵盖父表周期的整个周期

时间:2019-09-19 16:55:05

标签: sql oracle

我有两个表,分别是客户合同周期表和客户合同地点周期表。

客户合同周期表(PARENT表1)

ID         Customer_ID     Contract_ID    START_DATE    END_DATE
5215436    128             569            2/1/2015      6/25/2017

客户合同定位周期表(CHILD表2)

ID          Customer_ID   Client_ID   LOCATION_ID CUSTOMER_CONTRACT_CYCLE_ID    START_DATE  END_DATE
37361952     128          284187      3477623       5215436                     2/1/2015    12/31/2016
112243088    128          284187      3477623       5215436                     1/1/2017    6/25/2017

表1中的ID列是表2中的外键,因为CUSTOMER_CONTRACT_CYCLE_ID列是

在我的示例中,单个客户合同有两个客户合同定位周期,而两个(Customer_ID, Client_ID, LOCATION_ID, CUSTOMER_CONTRACT_CYCLE_ID)覆盖了整个客户合同周期。父子周期之间没有间隙,并且多个子周期涵盖了整个客户合同周期。但是我想找出那些客户合同定位周期,这些周期不能完全涵盖给定(Customer_ID, Client_ID, LOCATION_ID, CUSTOMER_CONTRACT_CYCLE_ID)的客户合同周期。

2 个答案:

答案 0 :(得分:0)

您需要查找四种情况:

  • 一个周期内完全没有位置(位置表中没有行)。
  • 缺少一个周期的开始位置(将位置与周期开始进行比较)。
  • 缺少一个循环的结束位置(将位置与循环结束进行比较)。
  • 缺少一个循环的中间位置(相邻位置之间的比较)。

以下查询搜索所有四种情况:

with 
s (id, start_date, end_date, ls, le, prev_end, next_start) as (
  select
    c.id,
    l.start_date, 
    l.end_date,
    lag(end_date) over(partition by c.id order by l.start_date),
    lead(start_date) over(partition by c.id order by l.start_date)
  from customer_contract_cycles c
  left join customer_contract_location_cycles l
            on c.id = l.customer_contract_cycle_id
)
select 'no locations at all for the cycle' as message, id, start_date, end_date
from s
where ls is null or le is null
union all

select 'no location at start of cycle', id, start_date, end_date
from s
where prev_end is null and le <> start_date
union all

select 'no location at end of cycle', id, start_date, end_date
from s
where next_start is null and le <> end_date
union all

select 'no location in middle of cycle', id, start_date, end_date
from s
where next_start is not null and next_start <> le + 1

答案 1 :(得分:0)

从经验上讲:如果有机会,请重新定义end_date。 在您的示例中,end_date是12月31日,下一个start_date是januari 1日。实际上,有两个日期表示 :第一个客户合同定位周期一直持续到第31个整个 12月,所以直到januari 1日?

在使用start + end定义期间时,如果将end_date定义为紧随实际结束时间,它将使计算和过滤更加容易。 有时使用[start_date, end_date[表示法:句点中未包含end_date

这样设置数据后,您只需执行where previous.end_date = next.start_date。这也使您可以使用简单的索引(而不是end_date+1上基于函数的索引)。

一种替代方法是了解 Interval数据类型。通过定义,它定义了时间长度:使用start_date字段和duration字段而不是start_date, end_date。 减去日期,例如next.start_date - previous.start_date会返回一个间隔,因此您可以在next.start_date-previous.start_date <= prevous.duration上进行过滤。

我想教给您的是,对数据进行不同的建模可以使以后的编程变得容易得多。