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

Posted

技术标签:

【中文标题】计算 T-SQL 中两个日期范围之间的交叉点数【英文标题】:Count Number of Intersections Between Two Date Ranges in T-SQL 【发布时间】:2016-07-13 12:12:16 【问题描述】:

我有以下两个表(显示了一些示例数据):

节假日

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

【问题讨论】:

你能展示一个你想要的样本输出吗? 上周是在 2000 年 2 月 31 日之后.... 查看更新的问题。 2000-02-31 是一个有效的日期吗?这些 Start 和 End 列是什么类型的? 但是没有 2 月 31 日这样的日期。当您尝试设置此类日期时,它将返回一个超出范围的异常。 【参考方案1】:

样本数据

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 中与给定事件的周相交的所有行的列表。交叉点持续时间从max of startsmin 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

【讨论】:

【参考方案2】:

尝试以下查询。

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

【讨论】:

【参考方案3】:

此查询还管理事件日期属于假日期间的情况。

 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

【讨论】:

以上是关于计算 T-SQL 中两个日期范围之间的交叉点数的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server - where + TVF/SVF、交叉应用、T-SQL

实验8-SPSS交叉表分析

将 T-SQL 交叉应用转换为 Oracle

交叉熵

高级T-SQL第1级的阶梯:使用交叉连接来引入高级T-SQL

当目标不是单热时,如何计算 Pytorch 中 2 个张量之间的正确交叉熵?