在MySQL中删除连续重复行的有效方法

时间:2012-11-22 12:25:18

标签: mysql sql duplicate-removal

我有一个包含(PROPERTY_ID, GPSTIME, STATION_ID, PROPERTY_TYPE, VALUE)列的表格,其中PROPERTY_ID是主键,STATION_ID是外键。

此表记录状态变化;每行代表某个站在给定时间的属性值。但是,它的数据是从旧表转换而来的,其中每个属性都是一列(如(STATION_ID, GPSTIME, PROPERTY1, PROPERTY2, PROPERTY3, ...))。因为通常只有一个属性在我有很多重复的时候发生了变化。

我需要删除所有具有相同值的连续行。

实施例。旧表包含像

这样的值
time  stn   prop1  prop2
100   7     red    large
101   7     red    small
102   7     blue   small
103   7     red    small

转换后的表格是

(order by time,type)          (order by type,time)
time  stn type  value         time  stn type value
100   7   1     red           100   7   1    red
100   7   2     large         101   7   1    red
101   7   1     red           102   7   1    blue
101   7   2     small         103   7   1    red
102   7   1     blue          100   7   2    large
102   7   2     small         101   7   2    small
103   7   1     red           102   7   2    small
103   7   2     small         103   7   2    small

应改为

time  stn type  value
100   7   1     red
100   7   2     large
101   7   2     small
102   7   1     blue
103   7   1     red

该表包含约22百万行。

我目前的方法是使用过程迭代表并删除重复项:

BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE id INT;
    DECLARE psid,nsid INT DEFAULT null;
    DECLARE ptype,ntype INT DEFAULT null;
    DECLARE pvalue,nvalue VARCHAR(50) DEFAULT null;
    DECLARE cur CURSOR FOR 
        SELECT station_property_id,station_id,property_type,value 
        FROM station_property 
        ORDER BY station_id,property_type,gpstime;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO id,nsid,ntype,nvalue;
        IF done THEN 
            LEAVE read_loop;
        END IF;        
        IF (psid = nsid and ptype = ntype and pvalue = nvalue) THEN
            delete from station_property where station_property_id=id;
        END IF;
        SET psid = nsid;
        SET ptype = ntype;
        SET pvalue = nvalue;
    END LOOP;
    CLOSE cur;
END

然而,它太慢了。在具有20000行的测试表上,它将删除10000个重复项,持续6分钟。有没有办法优化程序?

P.S。我仍然保持旧表的原样,所以也许最好尝试转换它而不需要重复,而不是在转换后处理重复项。

更新

澄清我想要允许哪些重复,哪些不重复。

  1. 如果属性发生更改,然后更改回来,我希望保存所有3条记录,即使第一个和最后一个包含相同的station_id,type和value。
  2. 如果有多个连续(通过GPSTIME)记录具有相同的station_id,type和value,我只想保存第一个(表示对该值的更改)。
  3. 简而言之,a -> b -> b -> a -> a应优化为a -> b -> a

    正如@Kickstart建议的那样,我创建了新表,填充了过滤后的数据。为了引用前面的行,我使用的方法类似于this question中使用的方法。

    rename table station_property to station_property_old;
    create table station_property like station_property_old;
    
    set @lastsid=-1;
    set @lasttype=-1;
    set @lastvalue='';
    
    INSERT INTO station_property(station_id,gpstime,property_type,value)
    select newsid as station_id,gpstime,newtype as type,newvalue as value from
    -- this subquery adds columns with previous values
        (select station_property_id,gpstime,@lastsid as lastsid,@lastsid:=station_id as newsid,
        @lasttype as lasttype,@lasttype:=property_type as newtype,
        @lastvalue as lastvalue,@lastvalue:=value as newvalue
        from station_property_old
        order by newsid,newtype,gpstime) sub
    -- we filter the data, removing unnecessary duplicates
    where lastvalue != newvalue or lastsid != newsid or lasttype != newtype;
    
    drop table station_property_old;
    

2 个答案:

答案 0 :(得分:1)

可能会创建一个新表,使用GROUP BY填充现有表中的select。像这样的东西(没有经过测试,可以解释任何错别字): -

INSERT INTO station_property_new
SELECT station_property_id, station_id, property_type, value 
FROM (SELECT station_property_id, station_id, property_type, value, COUNT(*) FROM station_property GROUP BY station_property_id, station_id, property_type, value) Sub1

答案 1 :(得分:1)

关于chainging属性,您无法设置唯一约束以确保站/类型/值列的组合是唯一的。这样,您将无法将其更改为导致重复的值。