Найти минимальную дату в диапазоне дат с sql - PullRequest
1 голос
/ 10 ноября 2011

Итак, у меня есть несколько таблиц истории, которые имеют дату начала и дату окончания.Проблема в том, что в этой таблице есть несколько записей, которые ссылаются на одну и ту же вещь, но их даты начала и окончания не точны.Итак, я пытаюсь объединить их даты начала и окончания.

Итак, каждый набор записей будет иметь даты начала и окончания закрытия (в течение примерно 7 секунд).Затем будет другой кластер с тем же ключом (в данном случае, VoyageID), но с другим набором дат начала и окончания закрытия.Имеет ли это смысл?Я могу опубликовать некоторые образцы данных, если это не так.

В любом случае, моя цель сейчас - найти минимальную дату начала для каждого кластера.То, что у меня есть сейчас, дает мне минимум для каждого VoyageID.Любая помощь будет оценена.Спасибо!

Вот что у меня есть:

DECLARE @7S DATETIME
SET @7S = '0:0:07'

PRINT @7S

SELECT MAX(T1.BeginDate), T1.VoyageID FROM
hist.VoyageProfitLossValues T1 INNER JOIN
hist.VoyageProfitLossValues T2 ON
T1.VoyageID = T2.VoyageID AND
T1.BeginDate BETWEEN (T2.BeginDate - @7S) and (T2.BeginDate + @7S)
GROUP BY T1.VoyageID

РЕДАКТИРОВАТЬ: Пример данных:

BeginDate                   EndDate                    VoyageID
2011-07-05 07:02:50.713     2011-07-05 07:25:53.007    6312
2011-07-05 07:02:50.870     2011-07-05 07:25:53.693    6312
2011-07-05 07:02:51.027     2011-07-05 07:25:54.387    6312
2011-07-08 14:22:21.147     NULL                       6312
2011-07-08 14:22:21.163     NULL                       6312
2011-07-08 14:22:21.177     NULL                       6312

Примечание: реальные данные имеют более 3 на каждый рейс, иBeginDates могут быть дальше друг от друга.

И я бы хотел из этого:

BeginDate                   VoyageID
2011-07-05 07:02:50.713     6312
2011-07-08 14:22:21.147     6312

То, что у меня есть, просто даст мне первую строку.

Я будув конечном итоге сделайте это и с конечной датой, но я могу легко преобразовать одну в другую.

Ответы [ 2 ]

2 голосов
/ 11 ноября 2011

Идея этого решения состоит в том, чтобы упорядочить ваши строки на BeginDate для каждого VoyageID.Пройдите сверху и выберите строки, которые имеют разницу во времени более 7 секунд, к предыдущей строке.

@Voy вместо hist.VoyageProfitLossValues.Сначала я создаю временную таблицу #T, которая заполнит столбец ID упорядоченными значениями для каждого VoyageID.C - это рекурсивный CTE, который начинается с ID = 1 и проходит через все строки, сравнивая текущую строку с предыдущей строкой и сохраняя результат в столбце FirstDate.Я добавил второй VoyageID к образцу данных, чтобы убедиться, что он также работает с этим.

declare @Voy table
(
  BeginDate datetime,
  EndDate datetime,
  VoyageID int
)

insert into @Voy values  
('2011-07-05 07:02:50.713',     '2011-07-05 07:25:53.007',    6312),
('2011-07-05 07:02:50.870',     '2011-07-05 07:25:53.693',    6312),
('2011-07-05 07:02:51.027',     '2011-07-05 07:25:54.387',    6312),
('2011-07-08 14:22:21.147',      NULL                    ,    6312),
('2011-07-08 14:22:21.163',      NULL                    ,    6312),
('2011-07-08 14:22:21.177',      NULL                    ,    6312),
('2011-07-05 07:02:50.713',     '2011-07-05 07:25:53.007',    6313),
('2011-07-05 07:02:50.870',     '2011-07-05 07:25:53.693',    6313),
('2011-07-05 07:02:51.027',     '2011-07-05 07:25:54.387',    6313),
('2011-07-08 14:22:21.147',      NULL                    ,    6313),
('2011-07-08 14:22:21.163',      NULL                    ,    6313),
('2011-07-08 14:22:21.177',      NULL                    ,    6313)


create table #T
(
  ID int,
  VoyageID int,
  BeginDate datetime
  primary key (ID, VoyageID)
)

insert into #T (ID, VoyageID, BeginDate)
select row_number() over(partition by VoyageID order by BeginDate),
       VoyageID,
       BeginDate
from @Voy     


;with C as
(
  select T.ID,
         T.VoyageID,
         T.BeginDate,
         1 as FirstDate
  from #T as T
  where T.ID = 1
  union all
  select T.ID,
         T.VoyageID,
         T.BeginDate,
         case when datediff(second, C.BeginDate, T.BeginDate) > 7 then 1 else 0 end
  from #T as T
    inner join C
      on T.ID = C.ID + 1 and
         T.VoyageID = C.VoyageID
)
select C.BeginDate,
       C.VoyageID
from C
where C.FirstDate = 1
order by C.VoyageID,
         C.BeginDate
option (maxrecursion 0)


drop table #T

Результат:

BeginDate               VoyageID
----------------------- -----------
2011-07-05 07:02:50.713 6312
2011-07-08 14:22:21.147 6312
2011-07-05 07:02:50.713 6313
2011-07-08 14:22:21.147 6313
0 голосов
/ 11 ноября 2011

Этот подход использует курсор. Я не знаю, является ли это правильным решением для вас:

create table #datacluster ( 
    dateCluster datetime, 
    dateV datetime primary key)

DECLARE @7S DATETIME
DECLARE @base DATETIME
DECLARE @begindate DATETIME

SELECT @base = SYSDATETIME()
SET @7S = '0:0:07'

DECLARE cursor1 CURSOR 
FAST_FORWARD READ_ONLY FOR    
SELECT distinct T1.BeginDate 
FROM
  hist.VoyageProfitLossValues T1 
ORDER BY  T1.BeginDate DESC

FETCH NEXT FROM cursor1 
INTO @begindate;    

WHILE @@FETCH_STATUS = 0
BEGIN

  IF @base - @7S > @begindate
  BEGIN
    set @base = @begindate
  END
  insert into #datacluster ( dateCluster, dateV) 
  values (@base,  @begindate)

  FETCH NEXT FROM cursor1 
  INTO @begindate;    
END

Обновить таблицу VoyageProfitLossValues ​​из #dataCluster:

UPDATE hist.VoyageProfitLossValues 
SET BeginDate = (
   SELECT C.BeginDate 
   FROM #datacluster C 
   WHERE 
      C.dateV = hist.VoyageProfitLossValues.BeginDate 
  )

Примечание 1: не тестировалось !!

Оптимизированный:

первичный ключ во временной таблице. быстрая перемотка вперед только для чтения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...