MySQL:从表中删除除20行之外的所有行?

时间:2013-04-22 11:45:29

标签: mysql

我有一个包含数十万行的表,分配给用户。 e.g:

itemid | userid | etc
1      | 1      | etc
2      | 1      | etc
3      | 1      | etc
4      | 3      | etc
5      | 3      | etc
6      | 3      | etc
etc    | etc    | etc

用户可以分配给他或她的任意数量的项目。即从0到无穷大的任何数字。我的问题是我想要一个SQL查询,它将删除每个用户的所有项目,但保留20.如果用户少于20,例如,只分配了10个项目,则必须保留所有10个。

我该怎么做?

更新

如果用户有50个项目,ID为1 - 50,则必须返回项目30 - 50.换句话说,该用户最后插入20个项目。

4 个答案:

答案 0 :(得分:2)

假设我们要删除除了每个用户最近的两个条目之外的所有条目......

CREATE TABLE my_table(itemid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,userid INT NOT NULL);

INSERT INTO my_table VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 3),
(5, 3),
(6, 3);

SELECT * FROM my_table;
+--------+--------+
| itemid | userid |
+--------+--------+
|      1 |      1 |
|      2 |      1 |
|      3 |      1 |
|      4 |      3 |
|      5 |      3 |
|      6 |      3 |
+--------+--------+

这是一个选择要删除的行的查询...

SELECT a.* 
  FROM my_table a 
  LEFT 
  JOIN 
     ( SELECT x.*, COUNT(*) FROM my_table x JOIN my_table y ON y.userid = x.userid AND y.itemid >= x.itemid GROUP BY x.itemid HAVING COUNT(*) <=2)b 
    ON b.itemid = a.itemid 
 WHERE b.itemid IS NULL;
+--------+--------+
| itemid | userid |
+--------+--------+
|      1 |      1 |
|      4 |      3 |
+--------+--------+

...这是一个删除它们的查询...

DELETE a 
  FROM my_table a 
  LEFT 
  JOIN 
     ( SELECT x.*, COUNT(*) FROM my_table x JOIN my_table y ON y.userid = x.userid AND y.itemid >= x.itemid GROUP BY x.itemid HAVING COUNT(*) <=2)b 
    ON b.itemid = a.itemid 
 WHERE b.itemid IS NULL;

SELECT * FROM my_table;
+--------+--------+
| itemid | userid |
+--------+--------+
|      2 |      1 |
|      3 |      1 |
|      5 |      3 |
|      6 |      3 |
+--------+--------+

答案 1 :(得分:0)

试试这个

     delete from Fruits where itemid  
     not in (select itemid from (select itemid from Fruits where userid = 1
     ORDER BY itemid desc limit 20)x  )
     and userid=1

DEMO HERE

答案 2 :(得分:0)

该代码的工作原理如下:

  • 创建一个新列:count - 计算每个用户的项目
  • 按itemid降序对结果进行排序 - 以便用户获得最高ID的第一个事件
  • 选择/删除所有具有count&gt;的行。 20 - 保留最后20(或更少)事件

SELECT:

SET @count=1;
SET @last_user_id=0;

SELECT * FROM (
SELECT *,
case 
when (@last_user_id = userid) 
then 
@count:=@count+1
else @count:=1 end as count,
case 
when (@last_user_id!=userid) 
then 
@last_user_id:=userid
end
as new
FROM <tablename> ORDER BY userid, itemid DESC) AS inner_table WHERE count > 20

删除:

SET @count=1;
SET @last_user_id=0;

DELETE FROM (
SELECT *,
CASE 
WHEN (@last_user_id = userid) 
THEN  
@count:=@count+1
ELSE 
@count:=1 
END 
AS count,
CASE 
WHEN (@last_user_id!=userid) 
THEN  
@last_user_id:=userid
END 
AS new
FROM <tablename> ORDER BY userid, itemid DESC) AS inner_table WHERE count > 20

答案 3 :(得分:-1)

这对我有用:

DELETE FROM table WHERE itemid NOT IN ( 
      SELECT itemid 
        FROM ( 
          SELECT * 
          FROM table
          WHERE userid = 1
          ORDER BY itemid  DESC 
          LIMIT 20
        ) x 
    ) 
    AND userid = 1