2014-08-28 2 views
0

Я пытаюсь очистить не столь полезную таблицу истории, изменив ее формат. Для использования таблицы истории важно, какое время была действительной строка.Перенос таблицы истории точек SQL Server в таблицу истории периодов

Текущая ситуация:

Unit | Value | HistoryOn  | 
---------------------------------------- 
1  | 123  | 2013-01-05 14:16:00 
1  | 234  | 2013-01-07 12:12:00 
2  | 325  | 2013-01-04 14:12:00 
1  | 657  | 2013-02-04 17:11:00 
3  | 132  | 2013-04-02 13:00:00 

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

мое решение создать таблицу в формат:

Unit | value | HistoryStart   | HistoryEnd   | 
--------------------------------------------------------------------- 
1  | 123  | 2013-01-05 14:16:00 | 2013-01-07 12:11:59 
1  | 234  | 2013-01-07 12:12:00 | 2013-02-04 17:10:59 
1  | 657  | 2013-02-04 17:11:00 | NULL 
2  | 325  | 2013-01-04 14:12:00 | NULL 
3  | 132  | 2013-04-02 13:00:00 | NULL 

Обратите внимание, что значение NULL в HistoryEnd здесь указывает, что строка все еще отражает текущий статус.

Я пробовал, чтобы использовать левое соединение на самом столе, используя поле HistoryOn. Это привело к неудачному побочному эффекту каскадирования нежелательным образом.

SQL Query используется:

SELECT * 
FROM webhistory.Units u1 LEFT JOIN webhistory.Units u2 on u1.Unit = u2.Unit 
    AND u1.HistoryOn < u2.HistoryOn 
WHERE u1.Units = 1 

Результат запроса выглядит следующим образом:

Unit | Value | HistoryOn   | Unit | Value | HistoryOn  | 
------------------------------------------------------------------------------------- 
    1  | 657  | 2013-02-04 17:11:00 | NULL | NULL | NULL 
    1  | 234  | 2013-01-07 12:12:00 | 1  | 657  | 2013-02-04 17:11:00 
    1  | 123  | 2013-01-05 14:16:00 | 1  | 657  | 2013-02-04 17:11:00 
    1  | 123  | 2013-01-05 14:16:00 | 1  | 234  | 2013-01-07 12:12:00 

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

К сожалению, пока я не могу найти хороший запрос для решения этой проблемы и хотел бы получить информацию или предложения, которые могли бы помочь мне решить эту проблему миграции.

ответ

1

Может быть, я что-то не хватает, но это похоже на работу:

CREATE TABLE #webhist(
    Unit int, 
    Value int, 
    HistoryOn datetime 
) 

INSERT INTO #webhist VALUES 
(1, 123, '2013-01-05 14:16:00'), 
(1, 234, '2013-01-07 12:12:00'), 
(2, 325, '2013-01-04 14:12:00'), 
(1, 657, '2013-02-04 17:11:00'), 
(3, 132, '2013-04-02 13:00:00') 

SELECT 
    u1.Unit 
    ,u1.Value 
    ,u1.HistoryOn AS HistoryStart 
    ,u2.HistoryOn AS HistoryEnd 
FROM #webhist u1 
OUTER APPLY (
    SELECT TOP 1 * 
    FROM #webhist u2 
    WHERE u1.Unit = u2.Unit AND u1.HistoryOn < u2.HistoryOn 
    ORDER BY HistoryOn 
) u2 

DROP TABLE #webhist 
+0

Спасибо за ответ, в то время как я не использовал это в качестве своего окончательного решения, он заставил меня посмотреть, где я ошибся. Вместо того, чтобы использовать OUTER APPLY, я предположил, что я использовал вложенный выбор: 'select *, (выберите top 1 historyon из #webhist u2, где u2.historyon> u1.historyon и u1.unit = u2.unit) от #webhist u1; ' – MSB

+0

Еще проще :) Рад помочь. –

1

образец первых данных

create table Data(
    Unit int, 
    Value int, 
    HistoryOn datetime) 

insert into Data 
select 1,123,'2013-01-05 14:16:00' 
union select 1  , 234  , '2013-01-07 12:12:00' 
union select 2  , 325  , '2013-01-04 14:12:00' 
union select 1  , 657  , '2013-02-04 17:11:00' 
union select 3  , 132  , '2013-04-02 13:00:00' 

Я создал функцию для вычисления HistoryEnd Заметил я назвал данные в таблице

CREATE FUNCTION dbo.fnHistoryEnd 
(
    @Unit as int, 
    @HistoryOn as datetime 
) 
RETURNS datetime 
AS 
BEGIN 
    -- Declare the return variable here 
    DECLARE @HistoryEnd as datetime 


    select top 1 @HistoryEnd=dateadd(s,-1,d.HistoryOn) 
    from Data d 
    where d.HistoryOn>@HistoryOn and [email protected] 
    order by d.HistoryOn asc 


    RETURN @HistoryEnd 

END 
GO 

Затем запрос тривиальна

select *,dbo.fnHistoryEnd(a.Unit,a.HistoryOn) from Data a 
order by Unit, HistoryOn 

EDIT

Не забудьте пункт order by в подзапросе. Посмотрите, что может произойти, если не

CREATE TABLE #webhist(
    Unit int, 
    Value int, 
    HistoryOn datetime 
) 

INSERT INTO #webhist VALUES 
(1, 234, '2013-01-07 12:12:00'), 
(2, 325, '2013-01-04 14:12:00'), 
(1, 657, '2013-02-04 17:11:00'), 
(3, 132, '2013-04-02 13:00:00'), 
(1, 123, '2013-01-05 14:16:00') 


select *, (select top 1 historyon from #webhist u2 where u2.historyon > u1.historyon and u1.unit = u2.unit) from #webhist u1; 
select *, (select top 1 historyon from #webhist u2 where u2.historyon > u1.historyon and u1.unit = u2.unit order by u2.HistoryOn) from #webhist u1; 

drop table #webhist 
+0

Спасибо за ответы, пока ваш метод работы я закончил с использованием иного подхода. – MSB

+0

@MSB Сначала я использовал ваш подход, но я не могу заставить его работать в sqlfiddle. Поэтому я положил sub querry в функцию. Не забывайте, что 'order by u2.HistoryOn' в вашем subquerry, как и в моей функции. Посмотрите мое изменение, чтобы уточнить. – Horaciux

Смежные вопросы