创建一个包含数百万行的表的上个月的视图

时间:2015-10-14 14:30:47

标签: sql-server

我有一个包含18000000行的表(TABLE_A)。我必须每15分钟执行一次存储过程,从TABLE_A中选择数据,进行一些计算并将结果插入另一个表(TABLE_B)。 TABLE_A的这个值来自包含不同设备读数的文件。因此,桌子会越来越大。

这是文件内容的示例:

'2015-10-01 11:00:00.000';'par01';1
'2015-10-01 12:00:00.000';'par02';1
'2015-10-01 12:00:00.000';'par03';1

我认为最好将来自文件的新值插入另一个表(TABLE_C),并使用TABLE_C的值进行计算。我想要一个查询,当一些变量达到一个月的数据时,将大于一个月的行插入TABLE_A(对我来说,一个月足以进行计算)。因此,在TABLE_C中只有一个月的数据,计算的执行将比使用18000000行更快。

这是表格的一个简单示例:

DECLARE @TABLE_C(timestamp datetime, parameter char(5),  value int)
DECLARE @TABLE_A(timestamp datetime, parameter char(5),  value int)

INSERT @TABLE_C values
('2015-10-01 11:00:00.000','par01',1),
('2015-10-01 12:00:00.000','par01',1),
('2015-09-01 11:03:00.000','par01',2),
('2015-09-01 12:03:00.000','par01',2),
('2015-08-01 11:06:00.000','par01',3),
('2015-08-01 12:06:00.000','par01',3),

('2015-09-01 11:00:00.000','par02',1),
('2015-09-01 12:00:00.000','par02',1),
('2015-08-01 11:03:00.000','par02',2),
('2015-08-01 12:03:00.000','par02',2),
('2015-07-01 11:06:00.000','par02',3),
('2015-07-01 12:06:00.000','par02',3),

('2015-10-01 11:00:00.000','par03',1),
('2015-10-01 12:00:00.000','par03',1),
('2015-09-01 11:03:00.000','par03',2),
('2015-09-01 12:03:00.000','par03',2),
('2015-08-01 11:06:00.000','par03',3),
('2015-08-01 12:06:00.000','par03',3)

结果必须是这样的:

INSERT @TABLE_C values
('2015-10-01 11:00:00.000','par01',1),
('2015-10-01 12:00:00.000','par01',1),


('2015-09-01 11:00:00.000','par02',1),
('2015-09-01 12:00:00.000','par02',1),


('2015-10-01 11:00:00.000','par03',1),
('2015-10-01 12:00:00.000','par03',1)

INSERT @TABLE_A values
('2015-09-01 11:03:00.000','par01',2),
('2015-09-01 12:03:00.000','par01',2),
('2015-08-01 11:06:00.000','par01',3),
('2015-08-01 12:06:00.000','par01',3),


('2015-08-01 11:03:00.000','par02',2),
('2015-08-01 12:03:00.000','par02',2),
('2015-07-01 11:06:00.000','par02',3),
('2015-07-01 12:06:00.000','par02',3),

('2015-09-01 11:03:00.000','par03',2),
('2015-09-01 12:03:00.000','par03',2),
('2015-08-01 11:06:00.000','par03',3),
('2015-08-01 12:06:00.000','par03',3)

1 个答案:

答案 0 :(得分:2)

编辑:这是一个新的解决方案。在开始时,它将计算每个参数及其开始和结束的上个月的边界。如果这很快将主要取决于"参数"中的不同值的计数。

而且:你需要索引!

SET LANGUAGE english;

DECLARE @t table(timestamp datetime, parameter char(5),  value int)

INSERT @t values
('2015-10-01 11:00:00.000','par01',1),
('2015-10-01 12:00:00.000','par01',1),
('2015-09-01 11:03:00.000','par01',2),
('2015-09-01 12:03:00.000','par01',2),
('2015-08-01 11:06:00.000','par01',3),
('2015-08-01 12:06:00.000','par01',3),

('2015-09-01 11:00:00.000','par02',1),
('2015-09-01 12:00:00.000','par02',1),
('2015-09-01 11:03:00.000','par02',2),
('2015-09-01 12:03:00.000','par02',2),
('2015-08-01 11:06:00.000','par02',3),
('2015-08-01 12:06:00.000','par02',3),

('2015-10-01 11:00:00.000','par03',1),
('2015-10-01 12:00:00.000','par03',1),
('2015-09-01 11:03:00.000','par03',2),
('2015-09-01 12:03:00.000','par03',2),
('2015-08-01 11:06:00.000','par03',3),
('2015-08-01 12:06:00.000','par03',3);

WITH MaxDates AS
(
    SELECT MAX(x.timestamp)  AS maxDate,x.parameter 
    FROM @t AS x
    GROUP BY x.parameter
)
,MonthFirst AS
(
    SELECT * 
          ,CONVERT(DATETIME, CAST(YEAR(maxDate) AS VARCHAR(4)) + CAST(REPLACE(STR(MONTH(maxDate),2),' ','0') AS VARCHAR(2)) + '01', 104) AS StartOfMonth
    FROM MaxDates
)
,MonthBorders AS
(
    SELECT *
          ,DATEADD(SECOND,-1,DATEADD(MONTH,1,StartOfMonth)) AS EndOfMonth
    FROM MonthFirst 
)
SELECT * 
FROM @t AS t
INNER JOIN MonthBorders AS mb ON t.parameter=mb.parameter AND t.timestamp BETWEEN mb.StartOfMonth AND mb.EndOfMonth
ORDER BY t.parameter;

一个增强功能可以是(保存一个DATEADD):

WITH MaxDates AS
(
    SELECT MAX(x.timestamp)  AS maxDate,x.parameter 
    FROM @t AS x
    GROUP BY x.parameter
)
,MonthFirst AS
(
    SELECT * 
          ,CONVERT(DATETIME, CAST(YEAR(maxDate) AS VARCHAR(4)) + CAST(REPLACE(STR(MONTH(maxDate),2),' ','0') AS VARCHAR(2)) + '01', 104) AS StartOfMonth
    FROM MaxDates
)
,MonthBorders AS
(
    SELECT *
          ,DATEADD(MONTH,1,StartOfMonth) AS EndOfMonth
    FROM MonthFirst 
)
SELECT * 
FROM @t AS t
INNER JOIN MonthBorders AS mb ON t.parameter=mb.parameter AND t.timestamp >= mb.StartOfMonth AND t.timestamp < mb.EndOfMonth
ORDER BY t.parameter;