簡體   English   中英

刪除所有行,對於一個查詢中表中具有相關行的每個客戶端,最后10條除外?

[英]Delete all rows, except last 10 for each client that has related row(s) in the table in one query?

所以我的情況是這樣的:

客戶表-具有客戶數據等,不太令人興奮

最近查看的表-最近查看過客戶端內容的表,其結構如下:

( 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

“ LIMIT 5”部分應限制N條記錄以“每位客戶”的形式保留在最近查看的表中。 現在,無論有多少客戶實際在其中查看記錄,它將最近查看的表中的記錄限制為5。 因此,如果我有10個客戶,每個客戶在該表中都有8條記錄,我希望此查詢刪除所需的最舊記錄,以便僅為EACH客戶保留5個最近查看的項目,而不僅僅是在表中保留5個最新記錄,忽略了“每個客戶”邏輯。 希望對你有意義:)

當前,如果我先獲取應用程序中的所有客戶端,然后執行foreach循環以對每個客戶端進行另一個查詢,並保留他最近查看的項目中的5個,則此查詢就可以了,但是我想在一個SQL查詢中執行此操作代替。

怎么辦呢? 謝謝

您可以這樣做:

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

您可以使用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            
)

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提供的思路來看一個解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM