删除除一个查询中表中相关行的每个客户端的最后10行以外的所有行?

时间:2016-03-07 12:12:40

标签: php mysql

所以我的情况是这样的:

客户表 - 有客户数据等,不太令人兴奋

最近查看过的表 - 最近查看过客户端内容的表,并且结构如下:

( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
, client_id INT NOT NULL
, cookie_user_id INT NOT NULL
, hotel_id INT NOT NULL
, added DATETIME NOT NULL
, comment TEXT
,status TINYINT NOT NULL DEFAULE 1
);

我目前有一个部分工作的SQL来删除最近查看的表中的行,这些行现在全局限制其中最新剩余的未删除记录的数量。这就是现在的样子

DELETE FROM `recently_viewed`
WHERE `recently_viewed`.`id` NOT IN (
        SELECT id 
          FROM ( 
            SELECT `id` 
            FROM `recently_viewed`
            WHERE `client_id` IN (SELECT `id` FROM `klijenti`)
            ORDER BY `id` DESC 
            LIMIT 5
        ) x 
     )
AND `client_id` <> 0

&#34;限制5&#34; part应限制为N个记录保留在最近查看的表中,每个客户端&#34;基础。现在它将最近查看的表中的记录限制为5,无论有多少客户实际上有记录。因此,如果我有10个客户端,每个客户端在该表中有8个记录,我希望此查询删除尽可能多的最旧记录,以便为EACH客户端仅留下最近最近查看的5个项目而不只是在表中留下5个,忽略每个客户的&#34;&#34;逻辑。希望对你有意义:))

目前,如果我首先获取应用程序中的所有客户端然后执行foreach循环以为每个客户端进行另一次查询并留下他最近最近查看过的5个项目,那么这个查询就没问题了,但是我想这样做而是一个SQL查询。

怎么可以这样做?谢谢

3 个答案:

答案 0 :(得分:3)

你可以这样做:

DELETE FROM `recently_viewed`
WHERE `recently_viewed`.`id` NOT IN (
        SELECT id 
          FROM ( 
            SELECT t.`id`,count(*) as rnk
            FROM `recently_viewed` t
            INNER JOIN `recently_viewed` s
            ON(t.`client_id` = s.`client_id` and t.added <= s.added)
            WHERE t.`client_id` IN (SELECT `id` FROM `klijenti`)
            GROUP BY t.`ID`
         ) x
        WHERE rnk <= 5
      )
AND `client_id` <> 0

答案 1 :(得分:1)

您可以使用vartiables来计算每client_id个最近的5条记录:

DELETE FROM `recently_viewed`
WHERE `recently_viewed`.`id` NOT IN 
(
   SELECT id 
   FROM ( 
        SELECT `id`,
               @rn := IF(@cid = `client_id`, @rn + 1,
                        IF(@cid := `client_id`, 1, 1)) AS rn
        FROM `recently_viewed`
        CROSS JOIN (SELECT @rn := 0, @cid := 0) AS vars
        WHERE `client_id` IN (SELECT `id` FROM `klijenti`)
        ORDER BY `client_id`, `id` DESC) x 
   WHERE x.rn <= 5            
)

答案 2 :(得分:1)

Giorgos的答案更快,但这是另一种方法...

考虑以下内容......

SELECT * FROM my_table ORDER BY x,i;
+---+------+
| i | x    |
+---+------+
| 2 | A    |
| 3 | A    |
| 6 | A    |
| 8 | A    |
| 1 | B    |
| 5 | B    |
| 4 | C    |
| 7 | C    |
| 9 | C    |
+---+------+

让我们说我们想为每个x选择两个最新的i。这是一种方法......

SELECT m.* FROM my_table m JOIN my_table n ON n.x = m.x AND n.i >= m.i GROUP BY m.i HAVING COUNT(*) <= 2;
+---+------+
| i | x    |
+---+------+
| 1 | B    |
| 5 | B    |
| 6 | A    |
| 7 | C    |
| 8 | A    |
| 9 | C    |
+---+------+

此集的反转可以如下找到....

SELECT m.* FROM my_table m JOIN my_table n ON n.x = m.x AND n.i >= m.i GROUP BY m.i HAVING COUNT(*) > 2;
+---+------+
| i | x    |
+---+------+
| 2 | A    |
| 3 | A    |
| 4 | C    |
+---+------+

...反过来可以合并到DELETE中。这是一个粗略的方法......

DELETE a FROM my_table a
  JOIN 
     ( SELECT m.* FROM my_table m JOIN my_table n ON n.x = m.x AND n.i >= m.i GROUP BY m.i HAVING COUNT(*) > 2 ) b
    ON b.i = a.i;
Query OK, 3 rows affected (0.03 sec)

SELECT * FROM my_table ORDER BY x,i;
+---+------+
| i | x    |
+---+------+
| 6 | A    |
| 8 | A    |
| 1 | B    |
| 5 | B    |
| 7 | C    |
| 9 | C    |
+---+------+

正如我所说,如果表现至关重要,那就看看Giorgos所提供的解决方案。