优化的sql查询删除行

时间:2012-10-07 16:18:49

标签: mysql sql database activerecord

我有一张看起来像这样的表: -

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是日期时间字段。 我需要在此表中仅保留10行(或更少),其中colC为0,10行(或更少),colC为1,最大总数为1。这些10行(每行)是最近的行,即10个最近的行(基于colD值),其0为colC值。类似地,保留ColC值为1的(最多)10行应该是前10行,其中1为ColC值。

目前,我正在解决4个查询以实现此目的。我为每个colC值触发一个查询为0和1以获取第11行(或更少)的时间戳。然后,对于获得的每个值,我触发另一个查询以删除所有“较旧”的行。

我可以触发一个查询来实现此目的吗?如果没有,那么最佳解决方案是什么?

PS: - 我在我的应用程序中使用活动记录,并且必须相应地修改查询。

2 个答案:

答案 0 :(得分: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行放在单独的表中,截断原始表,然后将其插入。

答案 1 :(得分: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

请注意,如果要删除超过50%的数据,您可能会发现SELECT要保留在新表中的记录更好,然后将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;