计算 T-SQL 中两个日期范围之间的交集数
Count Number of Intersections Between Two Date Ranges in T-SQL
我有以下两个表(显示了一些示例数据):
假期
Start | End
-----------|-----------
2000-01-01 | 2000-01-02
2000-02-20 | 2000-02-20
事件
Title | Date
-----------|-----------
Foo | 2000-01-03
Bar | 2000-01-20
如何 return 在 Event.Date
之前的一周内发生的具有假期天数的所有事件?
SELECT
e.Title,
e.Date,
DaysHolidayInPastWeek <-- How to get this?
FROM Event e
示例输出
Title | Date | DaysHolidayInPastWeek
-----------|------------|----------------------
Foo | 2000-01-03 | 2
Bar | 2000-01-20 | 0
尝试以下查询。
SELECT
e.Title,
e.Date,
(
SELECT
SUM(DATEDIFF(DAY, h.start, h.end)) AS CountOfHoliday
FROM
Holiday h
WHERE
h.EventId = e.Id AND -- releation id
h.Start >= DATEADD(DAY, -7, e.date) AND
h.Start <= e.date -- Or delete this. Just h.Start >= DATEADD(DAY, -7, e.date)
) AS DaysHolidayInPastWeek
FROM
Event e
示例数据
DECLARE @Holiday TABLE (HolidayStart date, HolidayEnd date);
INSERT INTO @Holiday (HolidayStart, HolidayEnd) VALUES
('2000-01-01', '2000-01-02'),
('2000-03-31', '2000-03-31'),
('2000-03-20', '2000-03-27'),
('2000-05-01', '2000-05-30');
DECLARE @Event TABLE (Title nvarchar(50), dt date);
INSERT INTO @Event (Title, dt) VALUES
('Foo', '2000-01-03'),
('Bar', '2000-01-20'),
('444', '2000-04-01'),
('555', '2000-05-10');
查询
假设 HolidayStart
和 HolidayEnd
日期都包含在内。
CROSS APPLY E
只是为 DATEADD
函数的结果创建方便的别名,这样我以后就可以写短的 EventStart
而不是长的 DATEADD
表达式。
OUTER APPLY
给出了 Holiday
中与给定事件的周相交的所有行的列表。交叉路口持续时间从 max of starts
到 min of ends
。
Main SELECT
将所有交叉点分组并求和。
SELECT
Ev.Title
,Ev.dt
,ISNULL(SUM(DATEDIFF(day,
Intersections.IntersectionStart,
Intersections.IntersectionEnd) + 1), 0) AS DaysHolidayInPastWeek
FROM
@Event AS Ev
CROSS APPLY
(
SELECT
DATEADD(day, -6, Ev.dt) AS EventStart
,Ev.dt AS EventEnd
) AS E
OUTER APPLY
(
SELECT
-- intersection duration is:
-- max of starts
-- min of ends
CASE WHEN E.EventStart > H.HolidayStart
THEN E.EventStart ELSE H.HolidayStart END AS IntersectionStart
,CASE WHEN E.EventEnd < H.HolidayEnd
THEN E.EventEnd ELSE H.HolidayEnd END AS IntersectionEnd
FROM @Holiday AS H
WHERE
-- two intervals intersect
H.HolidayEnd >= E.EventStart
AND H.HolidayStart <= E.EventEnd
) AS Intersections
GROUP BY
Ev.Title
,Ev.dt
;
结果
Title dt DaysHolidayInPastWeek
Foo 2000-01-03 2
Bar 2000-01-20 0
444 2000-04-01 3
555 2000-05-10 7
此查询还管理事件日期属于假期的情况。
SELECT Title, Date,
(
SELECT
sum(cntdays) from
(select start, [end],
case
when E.Date between start and [End]
then DATEDIFF(DAY, Start, E.Date)
when (
DATEADD(DAY, -7,E.Date) between start and [End]
or
DATEADD(DAY, -7,E.Date) < start
) and E.Date > start
then DATEDIFF(DAY, start, [end]) + 1
else 0
end as cntdays
from Holiday
) as H
) AS DaysHolidayInPastWeek
FROM Event AS E
我有以下两个表(显示了一些示例数据):
假期
Start | End
-----------|-----------
2000-01-01 | 2000-01-02
2000-02-20 | 2000-02-20
事件
Title | Date
-----------|-----------
Foo | 2000-01-03
Bar | 2000-01-20
如何 return 在 Event.Date
之前的一周内发生的具有假期天数的所有事件?
SELECT
e.Title,
e.Date,
DaysHolidayInPastWeek <-- How to get this?
FROM Event e
示例输出
Title | Date | DaysHolidayInPastWeek
-----------|------------|----------------------
Foo | 2000-01-03 | 2
Bar | 2000-01-20 | 0
尝试以下查询。
SELECT
e.Title,
e.Date,
(
SELECT
SUM(DATEDIFF(DAY, h.start, h.end)) AS CountOfHoliday
FROM
Holiday h
WHERE
h.EventId = e.Id AND -- releation id
h.Start >= DATEADD(DAY, -7, e.date) AND
h.Start <= e.date -- Or delete this. Just h.Start >= DATEADD(DAY, -7, e.date)
) AS DaysHolidayInPastWeek
FROM
Event e
示例数据
DECLARE @Holiday TABLE (HolidayStart date, HolidayEnd date);
INSERT INTO @Holiday (HolidayStart, HolidayEnd) VALUES
('2000-01-01', '2000-01-02'),
('2000-03-31', '2000-03-31'),
('2000-03-20', '2000-03-27'),
('2000-05-01', '2000-05-30');
DECLARE @Event TABLE (Title nvarchar(50), dt date);
INSERT INTO @Event (Title, dt) VALUES
('Foo', '2000-01-03'),
('Bar', '2000-01-20'),
('444', '2000-04-01'),
('555', '2000-05-10');
查询
假设 HolidayStart
和 HolidayEnd
日期都包含在内。
CROSS APPLY E
只是为 DATEADD
函数的结果创建方便的别名,这样我以后就可以写短的 EventStart
而不是长的 DATEADD
表达式。
OUTER APPLY
给出了 Holiday
中与给定事件的周相交的所有行的列表。交叉路口持续时间从 max of starts
到 min of ends
。
Main SELECT
将所有交叉点分组并求和。
SELECT
Ev.Title
,Ev.dt
,ISNULL(SUM(DATEDIFF(day,
Intersections.IntersectionStart,
Intersections.IntersectionEnd) + 1), 0) AS DaysHolidayInPastWeek
FROM
@Event AS Ev
CROSS APPLY
(
SELECT
DATEADD(day, -6, Ev.dt) AS EventStart
,Ev.dt AS EventEnd
) AS E
OUTER APPLY
(
SELECT
-- intersection duration is:
-- max of starts
-- min of ends
CASE WHEN E.EventStart > H.HolidayStart
THEN E.EventStart ELSE H.HolidayStart END AS IntersectionStart
,CASE WHEN E.EventEnd < H.HolidayEnd
THEN E.EventEnd ELSE H.HolidayEnd END AS IntersectionEnd
FROM @Holiday AS H
WHERE
-- two intervals intersect
H.HolidayEnd >= E.EventStart
AND H.HolidayStart <= E.EventEnd
) AS Intersections
GROUP BY
Ev.Title
,Ev.dt
;
结果
Title dt DaysHolidayInPastWeek
Foo 2000-01-03 2
Bar 2000-01-20 0
444 2000-04-01 3
555 2000-05-10 7
此查询还管理事件日期属于假期的情况。
SELECT Title, Date,
(
SELECT
sum(cntdays) from
(select start, [end],
case
when E.Date between start and [End]
then DATEDIFF(DAY, Start, E.Date)
when (
DATEADD(DAY, -7,E.Date) between start and [End]
or
DATEADD(DAY, -7,E.Date) < start
) and E.Date > start
then DATEDIFF(DAY, start, [end]) + 1
else 0
end as cntdays
from Holiday
) as H
) AS DaysHolidayInPastWeek
FROM Event AS E