2014-09-26 57 views
0

我想删除大于30天的表的所有记录,但保留每个ID的最后(最年轻)2记录。 我做了一些尝试与极限2和组合,但没有得到解决方案附近。有没有人有建议?复杂的删除查询

DROP TABLE IF EXISTS mytable; 

CREATE TABLE `mytable` (
    `timestamp` datetime NOT NULL, 
    `id` int(11) NOT NULL, 
    `data` varchar(100) NOT NULL, 
    PRIMARY KEY (`id`,`timestamp`) 
); 

INSERT INTO mytable VALUES 
('2014-08-12',22,'data'), 
('2014-08-13',22,'data'), 
('2014-08-14',22,'data'), 
('2014-08-15',22,'data'), 
('2014-08-16',54,'data'), 
('2014-08-16',22,'data'), 
('2014-08-17',54,'data'), 
('2014-08-18',54,'data'), 
('2014-08-19',54,'data'); 


Expected Result 
2014-08-15,22,data 
2014-08-16,22,data 
2014-08-18,54,data 
2014-08-19,54,data 

这是我迄今为止

sql = 'Delete from mytable where timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY)'; 
+0

这个数据集并没有很好的代表性,因为如果你放弃30天规则,你仍然会得到相同的结果! – Strawberry 2014-09-26 10:27:22

+1

而在数据库中你有'datetime'不是'date',所以在数据中你应该有'2014-08-19 12:35:57'例如 – DarkSide 2014-09-26 10:28:15

+0

嗨 - 我只是为了更好的可读性而举行日期 – ratmalwer 2014-09-26 10:43:43

回答

1
DELETE t 
FROM mytable t 
JOIN (
    SELECT id, SUBSTRING_INDEX(group_ts, ',', 2) AS two_ts 
    FROM (
    SELECT id, GROUP_CONCAT(timestamp ORDER BY timestamp DESC) AS group_ts 
    FROM mytable 
    WHERE timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY) 
    GROUP BY id 
) ag 
) tg ON tg.id = t.id AND FIND_IN_SET(t.timestamp, tg.two_ts) = 0 
WHERE timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY) 

我不认为它在大数据集上表现良好。虽然它会一直工作,直到日期组不超过group_concat_max_len。每组参加k条目的想法摘自xaprb blog post的评论。使用this SQL Fiddle玩查询。

+0

是的 - 这样做的工作! 我改变了查询,并在SELECT中删除了第一个:WHERE timestamp ratmalwer 2014-09-27 10:53:29

-1

不正确的解决方法:

DELETE FROM mytable a 
WHERE a.timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY)' 
    AND (a.id, a.timestamp) NOT IN (
     SELECT b.id, b.timestamp 
     FROM mytable b 
     GROUP BY b.id 
     ORDER BY b.id, b.timestamp desc 
     LIMIT 2 
    ) 

希望正确的解决办法:

DELETE FROM mytable a 
    LEFT JOIN (
     SELECT c.id, count(1) as cnt 
     FROM mytable c 
     GROUP BY c.id 
    ) b on a.id = b.id 
WHERE a.timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY)' 
    AND b.cnt > 2 
+0

Select选择节目该ID只有一次 - 与我发生的一样 – ratmalwer 2014-09-26 10:31:12

+0

是的第一个解决方案是错误的。你可以请再测试一下吗?我现在只是没有mysql来测试自己。 – DarkSide 2014-09-26 10:32:02

+0

你如何确保最旧的记录被删除?不知何故,我错过了一个订单。或者我忽略了什么? – ratmalwer 2014-09-26 10:42:37