使用匹配的多列查找最近的时间(SQL)

使用匹配的多列查找最近的时间(SQL),sql,database,Sql,Database,我有两个表:表1是在某个时间、日期、名称访问某个建筑物的通道 Accesses | Date | Time | Name | accesses| ----------------------------------------------- | 2018-10-10 | 10:10:34.00 | JA | 1 | | 2018-10-10 | 10:14:10.10 | AA | 1 |

我有两个表:表1是在某个时间、日期、名称访问某个建筑物的通道

Accesses

    |  Date      |    Time      | Name | accesses|
    -----------------------------------------------
    | 2018-10-10 |  10:10:34.00 |  JA  |     1   | 
    | 2018-10-10 |  10:14:10.10 |  AA  |     1   |
    | 2018-10-10 |  12:15:00.45 |  BE  |     1   |
    | 2018-10-10 |  15:00:00.50 |  JA  |     1   |
    | 2018-10-10 |  16:56:56.15 |  BE  |     1   |
表2显示了在某个访问过程中是否存在故障

Failure

    |  Date      |    Time      | Name | failure |
    -----------------------------------------------
    | 2018-10-10 |  10:10:40.00 |  JA  |     1   | 
    | 2018-10-10 |  10:15:06.00 |  AA  |     1   |
    | 2018-10-10 |  16:57:01.14 |  BE  |     1   |
期望输出

   Output

    |  Date      |    Time      | Name | accesses|  Failure |
    ---------------------------------------------------------
    | 2018-10-10 |  10:10:34.00 |  JA  |     1   |    1     |
    | 2018-10-10 |  10:14:10.10 |  AA  |     1   |    1     |
    | 2018-10-10 |  12:15:00.45 |  BE  |     1   |   NULL   |  
    | 2018-10-10 |  15:00:00.50 |  JA  |     1   |   NULL   |
    | 2018-10-10 |  16:56:56.15 |  BE  |     1   |    1     |

基本上,输出将包含访问,并将故障表与从访问表中检测到的最近时间相匹配。我尝试了不同的匹配时间戳的算法,但仍然会出现错误,因为并不是所有的访问都失败了,这就是为什么我希望在输出中使用NULL。从评论中感谢您,似乎这个加入条件会起作用

select distinct
    a.*
    ,Failure = case when f.Name is not null then 1 else null end
from Accesses a
left join Failure F on 
    f.Name = a.Name 
    and f.Time > dateadd(minute,-1, a.Time)
    and f.Time < dateadd(minute, 1, a.Time)
    and f.Date = a.Date 

数据库在表示时间的方式上有所不同。但是,一般的想法是,您可以使用以下方法:

这将使用值为0和1的标志。显然,您可以删除else 0子句以获得NULL而不是0


如果将日期和时间结合起来,这实际上会更加准确。根据数据的性质,可能不值得为午夜添加修复程序。

您对“最近的松动”的定义无法帮助您找到解决方案。但是为什么不运行一个联合查询,为第一个表添加一个虚拟的失败列,并按日期、时间和名称排序,这会对您有所帮助呢?mysql sql server和please define closestI删除了不兼容的数据库标记。请仅使用您真正使用的数据库进行标记。@如果日期和名称匹配,最接近的定义将在一分钟内完成,union将不起作用,因为我想为不起作用的访问显示NULLfail@scsimon最接近的将在一分钟内。如果在一次访问的一分钟内出现多个故障,则可能会复制行。谢谢!如果有一些记录的时间可能接近10秒或超过1分钟,你会怎么做?不,不超过1分钟,因为你说必须在一分钟内。你可以将dateadd函数中的-1和1更改为你想要的范围。谢谢!如果有一些记录的时间接近10秒或超过1分钟,你会怎么做?@AshA。你只需要调整时间的不平等性。
declare @Accesses table (Date date, Time time, Name char(2), accesses bit)
insert into @Accesses
values
('2018-10-10','10:10:34.00','JA',1 ),
('2018-10-10','10:14:10.10','AA',1),
('2018-10-10','12:15:00.45','BE',1),
('2018-10-10','15:00:00.50','JA',1),
('2018-10-10','16:56:56.15','BE',1),
('2018-10-10','23:59:56.15','XX',1)

declare @Failure table (Date date, Time time, Name char(2), failure bit)
insert into @Failure
values
('2018-10-10','10:10:40.00','JA',1), 
('2018-10-10','10:15:06.00','AA',1),
('2018-10-10','16:57:01.14','BE',1),
('2018-10-11','00:00:01.15','XX',1)



select distinct
    a.*
    ,Failure = case when f.Name is not null then 1 else null end
from @Accesses a
left join @Failure F on 
    f.Name = a.Name 
    and cast(convert(varchar,f.date) + ' ' + left(convert(varchar,f.time),8) as datetime) > dateadd(minute,-1,cast(convert(varchar,a.date) + ' ' + left(convert(varchar,a.time),8) as datetime))
    and cast(convert(varchar,f.date) + ' ' + left(convert(varchar,f.time),8) as datetime) < dateadd(minute,1,cast(convert(varchar,a.date) + ' ' + left(convert(varchar,a.time),8) as datetime))
select a.*,
       (case when exists (select 1
                          from failures f
                          where f.name = a.name and
                                f.date = a.date and
                                f.time > a.time - interval '1' minute and
                                f.time < a.time + interval '1' minute 
             then 1 else 0
        end) as failure_flag
from accesses a;