【问题标题】:SQL JOIN WITH A BUFFER TIME带有缓冲时间的 SQL 联接
【发布时间】:2013-03-18 13:12:34
【问题描述】:

我有两张表,必须检查一个表中的时间是否在其他表的范围之间。

ProgStartTime 给出范围的开始时间,ProgEndTime 给出位于 MBA 表中的范围的结束时间。 我正在检查 MAP 表中的 AdvTime 是否存在于 MBA 表的 ProgStartTime 和 ProgEndTime 之间。

对于小于一小时的时间范围,我必须提供 + 或 - 5 分钟的缓冲区。

即,如果 ProgStarttTime 是 18:00 并且 progEndTime 是 19:00 并且 AdvTime 是 17:55/19:05 它应该匹配范围。

而如果 ProgStarttTime 是 18:00 而 progEndTime 是 20:00 而 AdvTime 是 17:55 它不应该匹配。

不好意思内容有点匆忙。

我使用下面的查询来加入没有缓冲时间

SELECT DISTINCT mb.Id AS mbaid,
                mp.id AS mapid,
                mp.Channel AS Channel,
                mp.Product,
                mp.ProgDate,
                mp.AdvTime,
                mb.Channel,
                mb.ProgStartTime,
                mb.ProgEndTime,
                convert(time, dateadd(MINUTE, datediff(MINUTE, mb.progStartTime, mb.progEndTime), 0)) AS timeDiff
FROM map22 AS mp
INNER JOIN mba22 AS mb ON ((mp.ProgDate = mp.ProgDate
                            AND mp.Channel=mb.Channel
                            AND mp.Product=mb.Product))
WHERE (mp.ProgDate = mb.ProgDate
       AND AdvTime >= ProgStartTime
       AND (AdvTime <= ProgEndTime
            OR ProgEndTime < ProgStartTime))
  OR (mp.ProgDate = Dateadd(DAY,1,mb.ProgDate)
      AND ProgEndTime < ProgStartTime
      AND AdvTime <= ProgEndTime)
ORDER BY mp.Id ASC

【问题讨论】:

    标签: sql sql-server join


    【解决方案1】:

    您的示例查询有很多内容,因此我创建了一个简化示例。

    设置数据:

    create table MBA (MBAID int, ProgStartTime datetime, ProgEndTime datetime)
    
    insert into MBA select 1, '20130318 18:00:00', '20130318 19:00:00'
    insert into MBA select 2, '20130318 18:00:00', '20130318 20:00:00'
    
    create table Map (MapID int, AdvTime datetime)
    
    insert into Map select 1, '20130318 17:55:00'
    insert into Map select 2, '20130318 18:30:00'
    insert into Map select 3, '20130318 19:05:00'
    insert into Map select 4, '20130318 20:05:00'
    

    基于此,我们可以应用 CASE 语句,在日期相差一个小时或更短的情况下,给 AdvTime 更松散的匹配:

    select *
    from MBA
      inner join Map on
        MBA.ProgStartTime <=
          case when datediff(mi, MBA.ProgStartTime, MBA.ProgEndTime) <= 60
            then dateadd(mi, 5, Map.AdvTime)
            else Map.AdvTime
            end
        and MBA.ProgEndTime >=
          case when datediff(mi, MBA.ProgStartTime, MBA.ProgEndTime) <= 60
            then dateadd(mi, -5, Map.AdvTime)
            else Map.AdvTime
            end
    

    给出结果:

    我们可以看到,对于持续时间为一小时的 MBA 1,我们在稍微前后匹配 AdvTime 值,但对于 MBA 2,仅根据需要匹配时间段内的值。

    SQL Fiddle with demo.

    评论后编辑:

    为 cmets 中的值添加了另一个示例,包含以下数据:

    create table MBA (MBAID int, ProgStartTime datetime, ProgEndTime datetime)
    
    insert into MBA select 1, '20130318 21:00:00', '20130318 22:00:00'
    
    create table Map (MapID int, AdvTime datetime)
    
    insert into Map select 1, '20130318 20:55:00'
    insert into Map select 2, '20130318 22:05:00'
    

    原始查询按预期匹配上述两行。

    SQL Fiddle with demo.

    评论后编辑:

    用更多数据测试:

    create table MBA (MBAID int, ProgStartTime datetime, ProgEndTime datetime)
    
    insert into MBA select 1, '20130318 23:00:00', '20130319 02:00:00'
    
    create table Map (MapID int, AdvTime datetime)
    
    insert into Map select 1, '20130319 00:30:00'
    

    仍然符合预期。

    SQL Fiddle with demo.

    评论后的最终编辑?

    好的,现在我们对可以进行最终查询的架构有了更多了解。设置数据:

    create table MBA (MBAID int, ProgStartTime datetime, ProgEndTime datetime)
    
    insert into MBA select 1, '18:00:00', '19:00:00'
    insert into MBA select 2, '18:00:00', '20:00:00'
    insert into MBA select 3, '21:00:00', '22:00:00'
    insert into MBA select 4, '23:30:00', '02:00:00'
    insert into MBA select 5, '23:30:00', '00:30:00'
    
    
    create table Map (MapID int, AdvTime datetime)
    
    insert into Map select 1, '17:55:00'
    insert into Map select 2, '18:30:00'
    insert into Map select 3, '19:05:00'
    insert into Map select 4, '20:05:00'
    insert into Map select 5, '20:55:00'
    insert into Map select 6, '22:05:00'
    insert into Map select 7, '23:25:00'
    insert into Map select 8, '23:30:00'
    insert into Map select 9, '00:30:00'
    insert into Map select 10, '00:35:00'
    

    使用以下查询:

    select *
    from MBA
      inner join Map on
        (MBA.ProgStartTime < MBA.ProgEndTime
          and MBA.ProgStartTime <=
            case when datediff(mi, MBA.ProgStartTime, MBA.ProgEndTime) <= 60
              then dateadd(mi, 5, Map.AdvTime)
              else Map.AdvTime
              end
          and MBA.ProgEndTime >=
            case when datediff(mi, MBA.ProgStartTime, MBA.ProgEndTime) <= 60
              then dateadd(mi, -5, Map.AdvTime)
              else Map.AdvTime
              end) or
        (MBA.ProgStartTime > MBA.ProgEndTime
          and (MBA.ProgStartTime <=
            case when 1440 - datediff(mi, MBA.ProgEndTime, MBA.ProgStartTime) <= 60
              then dateadd(mi, 5, Map.AdvTime)
              else Map.AdvTime
              end
          or MBA.ProgEndTime >=
            case when 1440 - datediff(mi, MBA.ProgEndTime, MBA.ProgStartTime) <= 60
              then dateadd(mi, -5, Map.AdvTime)
              else Map.AdvTime
              end))
    

    我们希望匹配以下行:

    MBA  Matched Maps
    1    1,2,3
    2    2,3
    3    5,6
    4    8,9,10
    5    7,8,9,10
    

    结果:

    SQL Fiddle with demo.

    【讨论】:

    • 感谢您的宝贵时间。我需要另一种情况来解决。当持续时间(ProgStartTime - ProgEndTime)为一小时或更短时,我需要 + 或 - 5 分钟的缓冲区。如果我的 ProgstartTime 和 ProgEndtime 是 21:00:00 到 22:00:00。我需要 20:55:00/22:05:00 来匹配范围。
    • 原始查询也适用于上述值。我添加了一个 SQL Fiddle 来演示这一点。
    • 为混乱道歉> 考虑下面的场景 StartTme 23:00 EndTime 02:00 AdvTime 00:30 我需要它匹配范围。我之前为此使用了以下代码 select * from MBA inner join Map on MBA.ProgStartTime = case when datediff(mi, MBA.ProgStartTime, MBA.ProgEndTime)
    • 以上时间对我来说仍然匹配;请参阅上面的编辑和显示匹配行的新示例。
    • AM 在不同的列中有 Progdate 和时间,数据类型为 Date 和 Times,数据类型为 TIME。这就是我的不匹配的原因。请建议。我不能改变桌子设计
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多