我有两个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
如何使其与一个范围匹配而忽略另一个范围(最好与早期日期范围匹配)?
答案 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_date
从ranges
表中获取最少ranges
。在这里,我假设您在start_date
表格中的行不超过start_date
。
由于我们在上一步中有ranges
来自ranges
的表,我们可以再次连接到ranges_id
表,以检索start_date
和(如果需要)其他列 - end_date
和WITH 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来向您展示它是如何运作的。