2012-10-07 78 views
0

我有一个表,看起来有点像这样: -优化的SQL查询来删除行

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 

可乐COLB唯一标识一行。但是,它不是主要关键。 ColC可以是0或1. ColD是日期时间字段。 我需要只保留10行(或更少)从这个表中有colC为0和10行(或更少)colC为1,最大总数没有。的行数为20.这10行(每个)是最近的行,即最近的10行(基于colD值),其中0为colC值。类似地,ColC值保持为1的(最多)10行应该是具有1个ColC值的前10行。

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

我可以启动一个单一的查询来实现吗?如果不是,那么最佳解决方案是什么?

PS: - 我在我的应用程序中使用活动记录,将不得不相应地修改查询。

+0

你有什么话就可以做什么?你有没有工作的查询? –

+0

我试图使用groupby命令以某种方式获取一个查询中的时间戳值,然后删除另一个查询中的行。 –

+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行中的一个单独的表,截断原始表,然后将其插入。

+0

不错的尝试,但它在本地并不适合我。它并没有将每个组限制为只有10条记录。 –

+0

@RossSmithII。 。 。这很奇怪。该查询没有做任何复杂的事情。它只是选择20条记录来保留和删除其余记录。怎么了?你确定A和B是唯一标识每一行的吗? –

+0

我不确定毛刺在哪里,但看看http://sqlfiddle.com/#!2/51670/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;