如何删除每小时除一个以外的每条记录

时间:2014-10-23 20:17:58

标签: mysql sql

我有一个包含数百万个传感器记录的mysql表,其结构如下:

datanumber (auto increment), 
stationid (int), 
sensortype (int),
measuredate (datetime),
data (medtext)

每个站每2到10分钟(2-5个传感器)添加一条记录

我希望每个传感器每小时只保留一个记录 只有当测量值超过1年时,这也是如此。

我理解如何选择超过一年的数据,但我不清楚除了每小时一行之外如何删除行。如果它是每小时保留的第一个,最后一个或随机值并不重要。我也不需要计算平均值或其他东西,只需要删除存储的记录数量

3 个答案:

答案 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