SQL - 如何在一个时间跨度内查找记录

时间:2011-02-21 08:12:57

标签: sql sql-server tsql

我有两张桌子,一张有日期(让我们称之为Table1) - 让我们说只有两个字段:

RecordID
DateTime

另一个(表2)是信息记录和日期时间,如下所示:

RecordID
DateTime
Info1
Info2

我需要以某种方式获取Table1.RecordID,其中该记录的DateTime和下一个记录之间有一些条目。

假设我们已经进入了表1

1, 01/01/2010
2, 01/02/2010
3, 01/03/2010
4, 01/04/2010

和表2

10, 10/02/2010
11, 11/02/2010
12, 15/04/2010

因此,对于这些记录,我想得到Table1的记录,其中Table2中的条目在记录的DateTime之后到下一个记录(或者如果它是Table1中的最后一个记录,那么表2中的记录见表1)。

有什么想法吗? :)

P.S - 我使用MSSQL

编辑:更多信息。

谢谢!

3 个答案:

答案 0 :(得分:3)

如果table1中的RecordID是顺序的,没有间隙,这使我们的第一个任务更容易 - 我们需要从table1连接两行来表示我们感兴趣的时间跨度:

Table1 t1a
    inner join
Table1 t1b
    on
        t1a.RecordID = t1b.RecordID - 1

除了我们需要处理没有另一行要加入的最后一行,所以我们需要改为left join

Table1 t1a
    left join
Table1 t1b
    on
        t1a.RecordID = t1b.RecordID - 1

现在我们需要找出Table2中是否有适合此时间段的行。有两种明显的方法可以做到这一点 - 在where子句中进行EXISTS检查,或者使用DISTINCT进行额外的连接和过滤。哪一个更好地工作取决于许多因素,因此值得分析两者:

SELECT t1a.RecordID
FROM
Table1 t1a
    left join
Table1 t1b
    on
        t1a.RecordID = t1b.RecordID - 1
where exists(select * from Table2 t2 where t2.DateTime >= t1a.DateTime and (t2.DateTime < t1b.DateTime or t1b.DateTime is null))

或:

SELECT DISTINCT t1a.RecordID
FROM
Table1 t1a
    left join
Table1 t1b
    on
        t1a.RecordID = t1b.RecordID - 1
    inner join
Table2 t2
    on
        t2.DateTime >= t1a.DateTime and
        (t2.DateTime < t1b.DateTime or t1b.DateTime is null)

显然,可能需要调整大于和小于比较,这取决于我们构建的时间跨度的包容性或排他性上限和下限。


如果RecordID不是连续的,那么我们将转向搜索正确的行:

Table1 t1a
    left join
Table1 t1b
    on
        t1a.DateTime < t1b.DateTime
    left join
Table1 t1_nogap
    on
        t1a.DateTime < t1_nogap.DateTime and
        t1_nogap.DateTime < t1b.DateTime

我们现在第三次引用Table1(t1_nogap),并尝试连接适合t1a和t1b找到的行之间的行。

那么我们在where子句中添加一个额外的条件,因为我们不想使用t1a和t1b中的timepans,我们在这里找到了这样一行:

SELECT DISTINCT t1a.RecordID
FROM
Table1 t1a
    left join
Table1 t1b
    on
        t1a.DateTime < t1b.DateTime
    left join
Table1 t1_nogap
    on
        t1a.DateTime < t1_nogap.DateTime and
        t1_nogap.DateTime < t1b.DateTime
    inner join
Table2 t2
    on
        t2.DateTime >= t1a.DateTime and
        (t2.DateTime < t1b.DateTime or t1b.DateTime is null)
WHERE
    t1_nogap.RecordID is null

(显然,其他查询可以类似地重写)

答案 1 :(得分:0)

SELECT T1.ID, T1.DateTime 
FROM Table1 T1, Table2 T2
WHERE T2.DateTime BETWEEN T1.DateTime AND (SELECT MIN(T3.DateTime) 
FROM Table1 T3 WHERE T3.ID > T1.ID)
UNION ALL
SELECT T2.ID, T2.DateTime
FROM Table2 T2
WHERE T2.ID > (SELECT MAX(T1.ID) FROM Table1)

答案 2 :(得分:0)

也许这就是你想要的。

declare @T1 table (RecordID int, [DateTime] datetime)
declare @T2 table (RecordID int, [DateTime] datetime)

insert into @T1 values
(1, '2010-01-01'),
(2, '2010-02-01'),
(3, '2010-03-01'),
(4, '2010-04-01')

insert into @T2 values
(10, '2010-02-10'),
(11, '2010-02-11'),
(12, '2010-04-15')

select distinct T1_3.RecordID
from @T2 as T2
  inner join 
    (select
      T1_1.RecordID as RecordID,
      T1_1.[DateTime] as StartDate,
      (select top 1 T1_2.[DateTime]
       from @T1 as T1_2
       where T1_1.[DateTime] < T1_2.[DateTime]) as EndDate
    from @T1 as T1_1) as T1_3
  on T2.[DateTime] >= T1_3.StartDate and
     T2.[DateTime] < coalesce(T1_3.EndDate, '9999-12-31')