簡體   English   中英

計算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

如何返回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

樣本數據

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

詢問

假設HolidayStartHolidayEnd日期都包含在內。 CROSS APPLY E只是為DATEADD函數的結果創建了方便的別名,因此我可以稍后編寫簡短的EventStart而不是長DATEADD表達式。

OUTER APPLY給出Holiday中與給定Event的周相交的所有行的列表。 交叉持續時間從max of startsmin of ends

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 
    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

此查詢還管理事件日期屬於假日期間的情況。

 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