事件发生在一个事件的开始日期和另一个事件的结束日期

时间:2015-08-06 21:22:54

标签: sql

我有两个sql表

declare @events table (id int, [event date] date)

declare @ranges table (id int, [start date] date, [end date] date)

我尝试使用以下查询将事件与范围匹配

select 
    e.id as eid, r.id as rid
from 
    @events as e
inner join 
    @ranges as r on (e.[event date] between r.[start date] and r.[end date]);

我遇到的问题是,如果事件日期是一个事件的结束日期和另一个事件的开始日期,它将在查询结果中显示两次。该事件应仅匹配一个事件。例如

insert into @events values(1, '2014-01-02'); --date falls on end date on one event and start date of another event

insert into @ranges values(2, '2014-01-01','2014-01-02'),(3,'2014-01-02','2014-01-04');`  

我得到以下结果

eid  | rid
1        2 
1        3

如何使其与一个范围匹配而忽略另一个范围(最好与早期日期范围匹配)?

2 个答案:

答案 0 :(得分:0)

假设日期范围按递增顺序输入,则以下查询应该有效。如果没有,则无法保证您将获得在开始日期而非结束日期匹配的那个。

select orig.eid, min(orig.rid)
from (
    select e.id as eid, r.id as rid
    from  @events as e
        inner join @ranges as r
            on (e.[event date] between r.[start date] and r.[end date])
) as orig
group by orig.eid

答案 1 :(得分:0)

自@ GPicazos'答案并未涵盖您之后添加的start_date表格中ranges更早ranges.id表示的情况,因为ranges.id没有date需要确定存储在此ranges列中的值{我发布此答案。

我只会向您展示如何处理cte_events表中具有多个匹配项的行。这基本上就是你所问的。我将后一种情况(只有一次匹配)作为练习给你,因为它不涉及复杂的查询。

我们从您的查询开始events_multiple_matches

然后,下一个CTE event_id's仅输出具有多个匹配项的events_first_date_range

下一步 - start_dateranges表中获取最少ranges。在这里,我假设您在start_date表格中的行不超过start_date

由于我们在上一步中有ranges来自ranges的表,我们可以再次连接到ranges_id表,以检索start_date和(如果需要)其他列 - end_dateWITH cte_events AS ( SELECT e.id AS event_id, e.event_date FROM events e INNER JOIN ranges r ON e.event_date BETWEEN r.start_date AND r.end_date ) , events_multiple_matches AS ( SELECT event_id FROM cte_events GROUP BY event_id HAVING COUNT(*) > 1 ) , events_first_date_range AS ( SELECT e.event_id, MIN(r.start_date) AS min_start_date FROM cte_events e INNER JOIN events_multiple_matches em ON e.event_id = em.event_id INNER JOIN ranges r ON e.event_date BETWEEN r.start_date AND r.end_date GROUP BY e.event_id ) SELECT e.event_id, r.id AS ranges_id, r.start_date, r.end_date FROM events_first_date_range e INNER JOIN ranges r ON e.min_start_date = r.start_date

希望这会有所帮助。在代码下面,我附上了一个SQL小提示你的例子。

SELECT
  create_date
  ,resolved_date
  ,item
  ,site
  ,status
  ,contact_time
  ,impact_label
FROM
  mytable  
WHERE
  create_date BETWEEN to_date('2013/03/01','YYYY/MM/DD') 
   AND to_date('2015/08/06','YYYY/MM/DD')
and CASE item 
  WHEN in ('A','B') then '1'
  WHEN in ('C') then '2'
  WHEN in ('D') then '3'
  ELSE null 
  END 
GROUP BY
create_date
,resolved_date
,item
,site
,status
,contact_time
,impact_label

这里有一个SQL fiddle来向您展示它是如何运作的。