0

私はこのように見えるテーブルを持っています:-

A      B        C         D 
1      2        0         2012-10-05 18:37:00
1      3        0         2012-10-05 20:37:00
1      4        1         2012-04-07 18:37:00
2      1        1         2012-10-05 18:12:40
2      2        0         2012-10-04 18:37:00
2      3        0         2011-10-05 12:37:00

ColA と ColB は行を一意に識別します。ただし、主キーではありません。ColC は 0 または 1 のいずれかです。ColD は日時フィールドです。このテーブルから、colC が 0 の 10 行 (またはそれ以下) と、colC が 1 の 10 行 (またはそれ以下) だけを保持する必要があります。これらの 10 行 (それぞれ) は最新の行です。つまり、colC 値として 0 を持つ最新の 10 行 (colD 値に基づく) です。同様に、保持される ColC 値が 1 の (最大) 10 行は、ColC 値が 1 の最初の 10 行である必要があります。

現在、これを達成するために 4 つのクエリを実行しています。colC 値を 0 と 1 としてそれぞれ 1 つのクエリを実行して、11 行目 (またはそれ以下) のタイムスタンプを取得します。次に、取得した値ごとに別のクエリを起動して、すべての「古い」行を削除します。

これを達成するために単一のクエリを起動できますか? そうでない場合、これに対する最適な解決策は何ですか?

PS:- アプリケーションでアクティブ レコードを使用しており、それに応じてクエリを変更する必要があります。

4

2 に答える 2

3

これは機能します ( http://sqlfiddle.com/#!2/161af/1を参照):

delete from t
where not exists (select 1
                  from ((select A, B
                         from t
                         where C = 0
                         order by D desc
                         limit 10
                        ) union all
                        (select A, B
                         from t
                         where C = 1
                         order by D desc
                         limit 10
                        )
                       ) a
                  where a.A = t.A and a.B = t.B
                 )

これにより、保持する 20 個の値のリストが作成され、残りは削除されます。

パフォーマンスが問題になる場合は、20 行を別のテーブルに配置し、元のテーブルを切り捨ててから挿入することをお勧めします。

于 2012-10-07T18:32:06.440 に答える
1

これはあなたのために働くはずです:

DELETE
  ex
FROM
  ex
INNER JOIN
(
  SELECT
    C, MIN(D) D
  FROM
  (
    (
      SELECT
        C, D
      FROM
        ex
      WHERE
        C = 0
      ORDER BY
        D DESC
      LIMIT 10
    ) UNION (
      SELECT
        C, D
      FROM
        ex
      WHERE
        C = 1
      ORDER BY
        D DESC
      LIMIT 10
    )
  ) d1
  GROUP BY
    C
  ORDER BY
    C
) d2 ON d2.C = ex.C
WHERE
  ex.D < d2.D

上記のクエリを実行した後、

SELECT 
  C,
  COUNT(*),
  MIN(D),
  MAX(D)
FROM 
  ex
GROUP BY
  C
ORDER BY
  C

戻り値:

C   cnt MIN(D)                  MAX(D)
0   10  10/5/2012 2:14:53 AM    10/5/2012 7:21:23 PM
1   10  10/2/2012 1:41:21 PM    10/5/2012 2:57:34 PM

実際の例については、 SQL Fiddleを参照してください。

SELECTデータの 50% 以上を削除する場合は、保持したいレコードを新しいテーブルに保存してから、RENAMEこのテーブルを既存のテーブルに保存する方がよいことに注意してください。

次に例を示します。

DROP TABLE IF EXISTS ex_old;
DROP TABLE IF EXISTS ex_new;
CREATE TABLE ex_new LIKE ex;

INSERT INTO
    ex_new
SELECT
    ex.*
FROM
    ex
INNER JOIN
(
  SELECT
    C, MIN(D) D
  FROM
  (
    (
      SELECT
        C, D
      FROM
        ex
      WHERE
        C = 0
      ORDER BY
        D DESC
      LIMIT 10
    ) UNION (
      SELECT
        C, D
      FROM
        ex
      WHERE
        C = 1
      ORDER BY
        D DESC
      LIMIT 10
    )
  ) d1
  GROUP BY
    C
  ORDER BY
    C
) d2 ON d2.C = ex.C
WHERE
  ex.D >= d2.D;

RENAME TABLE ex TO ex_old, ex_new TO ex;
于 2012-10-07T18:13:33.083 に答える