从MySQL DB中删除重复项

时间:2015-05-12 19:35:10

标签: mysql datetime

我有一个拥有超过7000条记录的数据库。事实证明,这些记录中有几个重复。我找到了一些关于如何删除重复项并且只保留1条记录的建议。 但在我的情况下,事情有点复杂:如果案例与另一条记录保持相同的数据,则不仅仅是重复。相反,几个案例完全可以保持相同的数据。只有当它们保存相同的数据并且都在30秒内插入时,它们才被标记为重复。

因此,我需要一个删除重复项的SQL语句(例如:除<form>id之外的所有字段),如果它们已在40秒范围内插入(例如:评估datetime } field。。

由于我是除了SQL专家之外的所有人,并且无法在线找到合适的解决方案,我真的希望你们中的一些人可以帮助我并指出我正确的方向。非常感谢!

表结构如下:

datetime

所以,为了再次澄清,重复的案例是:

除了CREATE TABLE IF NOT EXISTS `wp_ttr_results` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `schoolyear` varchar(10) CHARACTER SET utf8 DEFAULT NULL, `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `area` varchar(15) CHARACTER SET utf8 NOT NULL, `content` varchar(10) CHARACTER SET utf8 NOT NULL, `types` varchar(100) CHARACTER SET utf8 NOT NULL, `tasksWrong` varchar(300) DEFAULT NULL, `tasksRight` varchar(300) DEFAULT NULL, `tasksData` longtext CHARACTER SET utf8, `parent_id` varchar(20) DEFAULT NULL, UNIQUE KEY `id` (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=68696 ; id字段

之外,

[1]包含与所有字段的其他案例相同的数据

[2]根据datetime字段在数据库中插入,在另一条具有相同值的记录的40秒内

如果满足两个条件,则应删除除一个以外的所有情况。

2 个答案:

答案 0 :(得分:3)

正如@Juru在评论中指出的那样,我们需要一个手术刀来削减这个。但是,可以通过存储过程以迭代方式执行此操作。

首先,我们使用自联接来识别每条记录的第一个副本,这本身并不重复:

SELECT DISTINCT
  MIN(postdups.id AS id)
FROM wp_ttr_results AS base
INNER JOIN wp_ttr_results AS postdups
  ON base.id<postdups.id
  AND UNIX_TIMESTAMP(postdups.datetime)-UNIX_TIMESTAMP(base.datetime)<40
  AND base.user_id=postdups.user_id
  AND base.schoolyear=postdups.schoolyear
  AND base.area=postdups.area
  AND base.content=postdups.content
  AND base.types=postdups.types
  AND base.tasksWrong=postdups.tasksWrong
  AND base.tasksRight=postdups.tasksRight
  AND base.parent_id=postdups.user_id
LEFT JOIN wp_ttr_results AS predups
  ON base.id>predups.id
  AND UNIX_TIMESTAMP(base.datetime)-UNIX_TIMESTAMP(predups.datetime)<40
  AND base.user_id=predups.user_id
  AND base.schoolyear=predups.schoolyear
  AND base.area=predups.area
  AND base.content=predups.content
  AND base.types=predups.types
  AND base.tasksWrong=predups.tasksWrong
  AND base.tasksRight=predups.tasksRight
  AND base.parent_id=predups.user_id
WHERE predups.id IS NULL
GROUP BY base.id
;

这将选择所有以后记录(id)中的最低base.id<postdups.id,这些记录与现有记录具有相同的有效负载,并且在40秒内(UNIX_TIMESTAMP(dups) .datetime)-UNIX_TIMESTAMP(base.datetime)&lt; 40),但跳过那些本身重复的基本记录。在@Juru的示例中,:30记录会被点击,因为它是:00记录的副本,它本身不是重复记录,但:41记录会不会被点击,因为它只与:30重复,:00本身是CREATE TEMPORARY TABLE cleanUpDuplicatesTemp SELECT DISTINCT -- as above ; DELETE FROM wp_ttr_results WHERE id IN (SELECT id FROM cleanUpDuplicatesTemp) ; DROP TABLE cleanUpDuplicatesTemp ; 的副本。

我们有

现在我们必须删除此记录 - 因为MySQL无法从正在读取的表中删除,我们必须使用变量来实现:

SELECT DISTINCT

到目前为止,我们将删除每条记录的第一个副本,在此过程中可能会发生变化,这将被视为重复...

最后,我们必须遍历此过程,如果DELIMITER ;; CREATE PROCEDURE cleanUpDuplicates() BEGIN DECLARE numDuplicates INT; iterate: LOOP DROP TABLE IF EXISTS cleanUpDuplicatesTemp; CREATE TEMPORARY TABLE cleanUpDuplicatesTemp SELECT DISTINCT MIN(postdups.id AS id) FROM wp_ttr_results AS base INNER JOIN wp_ttr_results AS postdups ON base.id<postdups.id AND UNIX_TIMESTAMP(postdups.datetime)-UNIX_TIMESTAMP(base.datetime)<40 AND base.user_id=postdups.user_id AND base.schoolyear=postdups.schoolyear AND base.area=postdups.area AND base.content=postdups.content AND base.types=postdups.types AND base.tasksWrong=postdups.tasksWrong AND base.tasksRight=postdups.tasksRight AND base.parent_id=postdups.user_id LEFT JOIN wp_ttr_results AS predups ON base.id>predups.id AND UNIX_TIMESTAMP(base.datetime)-UNIX_TIMESTAMP(predups.datetime)<40 AND base.user_id=predups.user_id AND base.schoolyear=predups.schoolyear AND base.area=predups.area AND base.content=predups.content AND base.types=predups.types AND base.tasksWrong=predups.tasksWrong AND base.tasksRight=predups.tasksRight AND base.parent_id=predups.user_id WHERE predups.id IS NULL GROUP BY base.id; SELECT COUNT(*) INTO numDuplicates FROM cleanUpDuplicatesTemp; IF numDuplicates<=0 THEN LEAVE iterate; END IF; DELETE FROM wp_ttr_results WHERE id IN (SELECT id FROM cleanUpDuplicatesTemp) END LOOP iterate; DROP TABLE IF EXISTS cleanUpDuplicatesTemp; END;; DELIMITER ; 没有返回任何内容,则退出循环。

将所有内容整合到一个存储过程中:

CALL cleanUpDuplicates;

现在一个简单的$database = new mysqli('localhost', 'username', 'password'); #see, no database selected $query1 = "select * from database1.tableX"; $res1 = $database->query($query1); $query2 = "select * from database2.tableY"; $res2 = $database->query($query2); 应该可以解决问题。

答案 1 :(得分:0)

这个可能有效,但可能不会很快......

DELETE FROM dupes 
USING wp_ttr_results AS dupes 
   INNER JOIN wp_ttr_results AS origs 
      ON dupes.field1 = origs.field1 
      AND dupes.field2 = origs.field2 
      AND ....
      AND AS dupes.id <> origs.id 
      AND dupes.`datetime` BETWEEN orig.`datetime` AND (orig.`datetime` + INTERVAL 40 SECOND)
;