我有一个包含数百万个传感器记录的mysql表,其结构如下:
datanumber (auto increment),
stationid (int),
sensortype (int),
measuredate (datetime),
data (medtext)
每个站每2到10分钟(2-5个传感器)添加一条记录
我希望每个传感器每小时只保留一个记录 只有当测量值超过1年时,这也是如此。
我理解如何选择超过一年的数据,但我不清楚除了每小时一行之外如何删除行。如果它是每小时保留的第一个,最后一个或随机值并不重要。我也不需要计算平均值或其他东西,只需要删除存储的记录数量
答案 0 :(得分:0)
您应该可以执行类似
的操作Select * from observations where <old> group by sensortype, stationid, extract(year_month, measure_date), extract(day_hour, measure_date);
group_by
会将每个组中的记录合并为一个。如果需要,可以将其选择到新表中。
如果您需要实际删除所有冗余旧记录,只需使用上述查询选择数据,然后删除所有记录NOT IN(<those ids>)
。
答案 1 :(得分:0)
如果要删除大量行,那么MySQL文档推荐的一种方法是选择要保留到临时表中的行,然后执行原子表重命名。也许是这样的:
INSERT INTO
sensordata_squeezed
SELECT
datanumber,
stationid,
sensortype,
measuredate,
data
FROM
sensordata
WHERE
measuredate < DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
GROUP BY
DATE_ADD(DATE(measuredate), INTERVAL HOUR(measuredate) HOUR),
stationid,
sensortype
UNION ALL
SELECT
datanumber,
stationid,
sensortype,
measuredate,
data
FROM
sensordata
WHERE
measuredate >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
;
RENAME TABLE
sensordata TO sensordata_old,
sensordata_squeezed TO sensordata
;
DROP TABLE sensordata_old
;
请注意:这依赖于MySQL关于从聚合查询中选择既不是组的列也不是组的聚合函数的列的记录行为:它从每个组中选择一个不确定的值。 (这是标准SQL的扩展。)我假设在每个组中,所有非聚合列值都来自同一行;您应该检查,因为该部分不已记录,并且此方法依赖于此以保持数据完整性。
这种方法允许您避免大型,昂贵的连接和大量子查询。
请注意,无论如何执行此操作,您将不得不解决如何避免在此操作运行时丢失数据的问题,因为这可能需要很长时间。
答案 2 :(得分:0)
如果我们可以使用row_number over( ... )
,这将是一个领先的管道,但MySQL的解决方案并不困难。对于这样的问题,看看我们是否可以查询我们想要删除的行的列表。这听起来很容易。首先,我们希望得到每天每小时的列表以及该小时的第一个(最少)条目:
select Date( MeasureDate ) TheDate, Hour( MeasureDate ) TheHour, Min( MeasureDate ) MinTime
from T
group by TheDate, TheHour;
所以我们只需要将表连接回这个结果集:
select T.*
from T
join(
select Date( MeasureDate ) TheDate, Hour( MeasureDate ) TheHour, Min( MeasureDate ) MinTime
from T
group by TheDate, TheHour
) as T1
on T1.MinTime = T.MeasureDate
这为我们提供了我们想要保持的所有行。因此,使用left join
反转结果:
select T.*
from T
left join(
select Date( MeasureDate ) TheDate, Hour( MeasureDate ) TheHour, Min( MeasureDate ) MinTime
from T
group by TheDate, TheHour
) as T1
on T1.MinTime = T.MeasureDate
where T1.MinTime is null;
将select
更改为delete
et viola:
delete TDel
from T TDel
left join(
select Date( MeasureDate ) TheDate, Hour( MeasureDate ) TheHour, Min( MeasureDate ) MinTime
from T
group by TheDate, TheHour
) as T1
on T1.MinTime = TDel.MeasureDate
where T1.MinTime is null;
您可以根据需要添加其他字段,例如SensorType
,以保持每个传感器每小时的首次输入,或者您想要调整它。 SqlFiddle