SQL - Как найти записи за промежуток времени - PullRequest
1 голос
/ 21 февраля 2011

У меня есть 2 таблицы, одна с датами (назовем это Table1) - скажем, только с 2 полями:

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

Таким образом, с этими записями я хотел бы получить Записи Таблицы1, где есть записи в Таблице 2 после DateTime записи до следующей (или, если это последняя запись в Таблице 1, записи в Таблице 2 после запись в таблице 1).

Есть идеи? :)

P.S. - Я использую MSSQL

РЕДАКТИРОВАТЬ: немного больше информации.

Спасибо!

Ответы [ 3 ]

3 голосов
/ 21 февраля 2011

Если идентификаторы RecordID в таблице1 являются последовательными, без пробелов, это облегчает нашу первую задачу - нам нужно объединить две строки из таблицы 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

Теперь нам нужно выяснить, есть ли в Таблице 2 какие-либо строки, подходящие для этого периода времени. Есть два очевидных способа сделать это - с помощью EXISTS проверки в предложении where или с помощью дополнительного объединения и фильтрации с использованием 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, где мы нашли такую ​​строку:

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

(и, очевидно, другой запрос может быть переписан аналогичным образом)

0 голосов
/ 21 февраля 2011

Возможно, это делает то, что вы хотите.

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')
0 голосов
/ 21 февраля 2011
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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...