将SQL Server点历史记录表迁移到期间历史记录表

时间:2014-08-28 12:49:34

标签: sql-server tsql data-migration

我试图通过改变它的格式来清理一个不太有用的历史表。 对于历史表的使用,行与哪个时间有效是相关的。

目前情况:

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

请注意,HistoryEnd中的NULL值表示该行仍然代表当前状态。

我已尝试使用HistoryOn字段在表格本身上使用左连接。这产生了以不希望的方式级联的不幸副作用。

使用的SQL查询:

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

此效果是增量的,因为每个条目都会加入比其自身更新的所有条目,而不是仅加入其后的第一个条目。

可悲的是,到目前为止,我无法提出一个好的查询来解决此问题,并希望能够帮助我解决此迁移问题的见解或建议。

2 个答案:

答案 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 d.Unit=@Unit
    order by d.HistoryOn asc


    RETURN @HistoryEnd

END
GO

然后,查询很简单

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

修改

不要忘记子查询中的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

答案 1 :(得分: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