2009-04-02 2 views
2

私はこのような何かを持っているところ、私はテーブルfooを持っていると仮定すると:MySQLで各ユーザーの最新Nでないすべての行を削除するにはどうすればよいですか?

idは、user_idtimestampは、some_value

私は何をしたいユーザーあたり、最新のN ないすべての行を削除しています。

削除自体はで扱うことができます:

DELETE FROM foo WHERE id NOT IN (...) 

ので、あなたに問題を修正してください可能性:どのように私は、行の各ユーザーについて(あまりがあるかもしれません)、最新のNを得るのですか。つまり、Uユーザーがいれば、N * U行になる可能性がありますので、LIMITは実際に動作しません。あなたの数でNを交換

DELETE FROM foo WHERE id NOT IN (...) ORDER BY timestamp ASC LIMIT (Count - N) 

:これを試して次に

SELECT COUNT(*) as total FROM foo WHERE id NOT IN (...) 

答えて

2

MySQLは、SELECTのテーブルからの読み込みと、同じクエリの同じテーブル上でUPDATE/INSERT7との実行をサポートしていません。したがって、あなたが望むことを1つの声明で行うことはやりにくいでしょう。、最初のユーザーごとの最新$Nレコードを照会し、一時テーブルに保存:

私は2つの段階でそれを行うだろう

CREATE TEMPORARY TABLE foo_top_n 
    SELECT f1.id 
    FROM foo f1 LEFT OUTER JOIN foo f2 
    ON (f1.user_id = f2.user_id AND f1.id < f2.id) 
    GROUP BY f1.id 
    HAVING COUNT(*) < $N; 

次に、マルチテーブルDELETE構文を使用してにfooに参加します一時テーブル、一致するものがないところ削除:

DELETE f1 FROM foo f1 LEFT OUTER JOIN foo_top_n f2 USING (id) 
WHERE f2.id IS NULL; 
0

まず、これを使用した行の合計数を取得します。これにより、最新のN行を除くすべてが削除されます。たとえば、 の場合、合計100行あり、最新の5を保存する場合は、最も古い95行が削除されます(100-5)。

+0

私は申し訳ありませんがわかりません、私はそれぞれのuser_idのN行を意味する – tliff

+0

この場合、クエリを次のように変更します。Where id = user_id。私はあなたが配列内のすべてのIDのリストを持っていると仮定し、各IDをループして、このクエリをそれらのために実行させます –

0
DELETE FROM foo WHERE id NOT IN (SELECT id FROM foo ORDER BY timestamp DESC LIMIT N) 

編集:

私は質問を誤解。各ユーザーごとにN個のレコードを保持する必要があります。 多分これ:各user_idのためのその後

SELECT user_id FROM foo 

(currentIDなど):

DELETE FROM foo WHERE user_id=currentID AND id NOT IN (SELECT id FROM foo WHERE user_id=currentID ORDER BY timestamp DESC LIMIT N) 

(私は構文については非常にわからないんだけど、私はアイデアが明らかであると思います)

+0

私は不明ですが、私は各user_idのN行を意味して申し訳ありません – tliff

3

は実際には、それを単一のクエリを行うことが可能です:

DELETE l.* 
FROM foo l 
JOIN (
     SELECT user_id, 
       COALESCE(
       (
       SELECT timestamp 
       FROM foo li 
       WHERE li.user_id = dlo.user_id 
       ORDER BY 
         li.user_id DESC, li.timestamp DESC 
       LIMIT 2, 1 
       ), CAST('0001-01-01' AS DATETIME)) AS mts, 
       COALESCE(
       (
       SELECT id 
       FROM foo li 
       WHERE li.user_id = dlo.user_id 
       ORDER BY 
         li.user_id DESC, li.timestamp DESC, li.id DESC 
       LIMIT 2, 1 
       ), -1) AS mid 
     FROM (
       SELECT DISTINCT user_id 
       FROM foo dl 
       ) dlo 
     ) lo 
ON  l.user_id = lo.user_id 
     AND (l.timestamp, l.id) < (mts, mid) 

ここで詳細な説明を参照してください:

+0

+1すばらしいクエリ – Bigbohne

関連する問題