简体   繁体   English

计算T-SQL中两个日期范围之间的交叉点数

[英]Count Number of Intersections Between Two Date Ranges in T-SQL

I have the following two tables (some sample data shown): 我有以下两个表(显示了一些示例数据):

Holiday 假日

Start      | End
-----------|-----------
2000-01-01 | 2000-01-02
2000-02-20 | 2000-02-20

Event 事件

Title      | Date
-----------|-----------
Foo        | 2000-01-03
Bar        | 2000-01-20

How can I return all events with the number of holiday days that have occurred during a week before Event.Date ? 如何返回Event.Date前一周内发生的假日天数?

SELECT 
    e.Title,
    e.Date,
    DaysHolidayInPastWeek  <-- How to get this?
FROM Event e

Example Output 示例输出

Title      | Date       | DaysHolidayInPastWeek
-----------|------------|----------------------
Foo        | 2000-01-03 | 2
Bar        | 2000-01-20 | 0

Sample data 样本数据

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

Query 询问

Assumes that HolidayStart and HolidayEnd dates are both inclusive. 假设HolidayStartHolidayEnd日期都包含在内。 CROSS APPLY E is just to create handy alias for the result of the DATEADD function, so that I could write short EventStart later instead of the long DATEADD expression. CROSS APPLY E只是为DATEADD函数的结果创建了方便的别名,因此我可以稍后编写简短的EventStart而不是长DATEADD表达式。

OUTER APPLY gives a list of all rows in the Holiday that intersect with the week of the given Event. OUTER APPLY给出Holiday中与给定Event的周相交的所有行的列表。 Intersection duration is from max of starts till min of ends . 交叉持续时间从max of startsmin of ends

Main SELECT groups and sums all intersections together. 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
;

Result 结果

Title       dt  DaysHolidayInPastWeek
Foo 2000-01-03  2
Bar 2000-01-20  0
444 2000-04-01  3
555 2000-05-10  7

Try following query. 尝试以下查询。

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

this query also manages cases in which event date falls into a holiday period. 此查询还管理事件日期属于假日期间的情况。

 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM