MYSQL替换表的一部分

时间:2019-02-01 16:38:05

标签: mysql

我有以下数据,它们增长得太快太快了:

c1    c2       timestamp
5      1       2019-01-31 15:35:36.055000
6      2       2019-01-31 15:35:36.055000
7      3       2019-01-31 15:35:35.055000
8      4       2019-01-31 15:35:35.055000
7      3       2019-01-30 15:35:36.055000
8      4       2019-01-30 15:35:36.055000
7      3       2019-01-30 15:35:35.055000
8      4       2019-01-30 15:35:35.055000

我想通过将时间戳上限设置为10秒钟来替换表的一部分,其中时间戳早于2019-01-31 00:00:00:000000 结果应该是这样,并且上述表中的底部两列不应在新表中:

c1    c2       timestamp
5      1       2019-01-31 15:35:36.055000
6      2       2019-01-31 15:35:36.055000
7      3       2019-01-31 15:35:35.055000
8      4       2019-01-31 15:35:35.055000
7      3       2019-01-30 15:35:40.000000
8      4       2019-01-30 15:35:40.000000

我执行了以下查询以取消时间戳记,但是我不知道如何替换表的特定部分。

SELECT c1, c2, FROM_UNIXTIME(CEIL(UNIX_TIMESTAMP(timestamp) / 10) * 10) as datetime 
FROM mytable
WHERE timestamp in (SELECT MAX(timestamp) FROM mytable
GROUP BY FROM_UNIXTIME(CEIL(UNIX_TIMESTAMP(timestamp) / 10) * 10)) 
GROUP BY datetime

2 个答案:

答案 0 :(得分:1)

像这样的查询将列出所有行的时间戳值

UPDATE mytable SET timestamp=FROM_UNIXTIME(CEIL(UNIX_TIMESTAMP(timestamp) / 10) * 10);

如果只想将其应用于某些行,请添加WHERE提示

答案 1 :(得分:1)

(注意:如果c1或c2可以为null,则在不进行重大修改的情况下,该解决方案可能对您不起作用。)

如果您只想保留每10秒一次的最新时间,则应执行以下操作:

DELETE 
FROM mytable
WHERE timestamp < '2019-01-31 00:00:00:000000'
    AND (c1, c2, timestamp) 
        NOT IN (
           SELECT ends.c1, ends.c2, ends.windowEnd
           FROM (  SELECT c1, c2
                      , FROM_UNIXTIME(CEIL(UNIX_TIMESTAMP(timestamp) / 10) * 10) as dtWindow
                      , MAX(timestamp) AS windowEnd
                   FROM mytable
                   WHERE timestamp < '2019-01-31 00:00:00:000000'
                   GROUP BY c1, c2, dtWindow
                ) AS ends
        )
;

注意:有时MySQL对于从同一查询中要从中删除的表中进行选择有些挑剔,但是我认为该子查询中的间接层级别足够高,这不应该成为问题。


奖金:如果要在运行此类查询之前仔细检查将要删除的记录,可以将子选择移到联接选择中以预览内容。

SELECT t.*
, CASE WHEN ends.rowPresent IS NOT NULL THEN 'keep' ELSE 'to delete' END AS `plan`
FROM mytable AS t 
LEFT JOIN (
   SELECT c1, c2
      , FROM_UNIXTIME(CEIL(UNIX_TIMESTAMP(timestamp) / 10) * 10) as dtWindow
      , MAX(timestamp) AS windowEnd
      , 1 AS rowPresent -- You could just use c1 or c2 in the above CASE, but if they could naturally be null that would complicate things
   FROM mytable
   WHERE timestamp < '2019-01-31 00:00:00:000000'
   GROUP BY c1, c2, dtWindow
) AS ends ON t.c1 = ends.c1 AND t.c2 = ends.c2 AND t.timestamp = ends.windowEnd
WHERE t.timestamp < '2019-01-31 00:00:00:000000'
;