这类问题在 MySQL 中有点不方便,因为他们没有实现像 ROW_NUMBER() 这样的 SQL-99 窗口函数。 MySQL 直到 8.0 版本才支持此功能。
这是一个适用于 MySQL 5.7 及更早版本的单个 SQL 语句的解决方案,并且只能选择每个组中大于第 200 个的成员。它使用了一个名为user variables 的 MySQL 功能,当您的查询过程逐行处理时,它会保持其价值。
DELETE f FROM foo AS f
JOIN (SELECT id, IF(@g = `group`, @rn:=@rn+1, @rn:=1) AS row_number, @g:=grp
FROM foo, (SELECT @g:=null, @rn:=0) _init
ORDER BY `group`, date desc) AS r
ON f.id = r.id AND r.row_number > 200;
在您运行此程序(或任何删除数据的程序!)之前,我建议您了解它的工作原理,并使用等效的 SELECT 对其进行测试,以确保它正在选择您要删除的行。
我用较小的数据集对此进行了测试。这是我在没有过滤的情况下运行它时的数据:
SELECT f.id, f.`group`, r.row_number FROM foo AS f
JOIN (SELECT id, IF(@g = `group`, @rn:=@rn+1, @rn:=1) AS row_number, @g:=grp
FROM foo, (SELECT @g:=null, @rn:=0) _init
ORDER BY `group`, date desc) AS r
ON f.id = r.id;
+----+--------+------------+
| id | group | row_number |
+----+--------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 5 | 1 | 4 |
| 11 | 1 | 5 |
| 4 | 2 | 1 |
| 10 | 2 | 2 |
| 8 | 2 | 3 |
| 7 | 3 | 1 |
| 6 | 3 | 2 |
| 12 | 3 | 3 |
| 9 | 4 | 1 |
+----+--------+------------+
这是跳过每组前 2 个的 SELECT:
SELECT f.id, f.`group`, r.row_number FROM foo AS f
JOIN (SELECT id, IF(@g = `group`, @rn:=@rn+1, @rn:=1) AS row_number, @g:=grp
FROM foo, (SELECT @g:=null, @rn:=0) _init
ORDER BY `group`, date desc) AS r
ON f.id = r.id AND r.row_number > 2;
+----+-------+------------+
| id | group | row_number |
+----+-------+------------+
| 3 | 1 | 3 |
| 5 | 1 | 4 |
| 11 | 1 | 5 |
| 8 | 2 | 3 |
| 12 | 3 | 3 |
+----+-------+------------+