我目前有PHP代码处理这个逻辑,因为我不知道如何在SQL中处理它。我想创建一个存储过程,删除除给定config_id的最新行之外的所有行。 IE config_id = 5传递给SP,因此它知道它要清理哪个config_id。
CREATE TABLE `TAA`.`RunHistory` (
`id` int(11) NOT NULL auto_increment,
`start_time` datetime default NULL,
`stop_time` datetime default NULL,
`success_lines` int(11) default NULL,
`error_lines` int(11) default NULL,
`config_id` int(11) NOT NULL,
`file_id` int(11) NOT NULL,
`notes` text NOT NULL,
`log_file` longblob,
`save` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=128 DEFAULT CHARSET=utf8;
最新将由start_time确定,如果stop_time为null但不是最新的应删除(如果运行被毫不客气地杀死,则stop_time可以为null)。
答案 0 :(得分:12)
从 SQL query: Delete all records from the table except latest N?:
DELETE FROM `runHistory`
WHERE id NOT IN (
SELECT id
FROM (
SELECT id
FROM `runHistory`
ORDER BY start_time DESC
LIMIT 5
) foo
);
答案 1 :(得分:1)
这是我在MySQL 5.1.46上测试过的一个过程,但是它没有使用子查询,所以你不会在子查询中得到关于不支持LIMIT
的错误。
CREATE PROCEDURE DeleteBut5(IN c INT) BEGIN
DECLARE i INT;
DECLARE s DATETIME;
SELECT id, stop_time INTO i, s
FROM RunHistory WHERE config_id = c
ORDER BY stop_time DESC, id DESC
LIMIT 4, 1;
DELETE FROM RunHistory WHERE stop_time < s OR stop_time = s AND id < i;
END
我建议您创建此覆盖索引:
CREATE INDEX cov ON RunHistory (config_id, stop_time, id);
答案 2 :(得分:0)
begin;
declare v_start_time datetime;
declare v_id int;
#Find the id of the newest run
select id into v_id from RunHistory where start_time = (select max(start_time) from RunHistory);
#delete null stop times except for the newest run
delete from RunHistory where stop_time is null and id != v_id;
#first row is 0... skip 0-4, show 5
select start_time into v_start_time from RunHistory order by stop_time desc limit 4,1;
delete from RunHistory where start_time < v_start_time;
end;
你去吧。我建议索引start_time。 Stop_time可能值得也可能不值得索引。可能不是。您可以通过将删除语句更改为以下内容来优化该语句,因为我们将删除前五个之后的任何内容:
delete from RunHistory where stop_time is null and id != v_id order by start_time desc limit 5;
答案 3 :(得分:0)
https://stackoverflow.com/a/8303440/2576076是一个很好的解决方案。 如果你的桌子有很多行,那就更好了。