单个查询中的Mysql重复数据删除记录

时间:2014-05-30 09:34:17

标签: mysql sql deduplication

我有下表:

CREATE TABLE `relations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `relationcode` varchar(25) DEFAULT NULL,
  `email_address` varchar(100) DEFAULT NULL,
  `firstname` varchar(100) DEFAULT NULL,
  `latname` varchar(100) DEFAULT NULL,
  `last_contact_date` varchar(25) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

在此表中有重复项,这些是完全相同的关系代码和email_address的关系。他们可以在那里两次甚至10次。 我需要一个查询来选择所有记录的ID,但不包括那些记录中的记录。在那些记录中,我只想选择最近只有last_contact_id的记录。

我在Oracle中比在Mysql中更多,在Oracle中我可以这样做:

select * from (
    select row_number () over (partition by relationcode order by to_date(last_contact_date,'dd-mm-yyyy')) rank, 
           id, 
           relationcode,  
           email_address , 
           last_contact_date
    from RELATIONS)
where rank = 1

但我无法弄清楚如何修改此查询以在MySql中工作。我甚至不敢在MySQl的单个查询中做同样的事情。 有什么想法吗?

2 个答案:

答案 0 :(得分:3)

执行此操作的常规方法是获取最新记录的子查询,然后将其与表格连接: -

SELECT id, relationcode, email_address, firstname, latname, last_contact_date
FROM RELATIONS
INNER JOIN
(
    SELECT relationcode, email_address, MAX(last_contact_date) AS latest_contact_date
    FROM RELATIONS
    GROUP BY relationcode, email_address
) Sub1
ON RELATIONS.relationcode = Sub1.relationcode
AND RELATIONS.email_address = Sub1.email_address
AND RELATIONS.last_contact_date = Sub1.latest_contact_date

可以使用变量手动生成Oracle查询使用的排名类型。虽然有点杂乱!

SELECT id, relationcode, email_address, firstname, latname, last_contact_date
FROM
(
    SELECT id, relationcode, email_address, firstname, latname, last_contact_date, @seq:=IF(@relationcode = relationcode AND @email_address = email_address, @seq + 1, 1) AS seq, @relationcode := relationcode, @email_address := email_address
    (
        SELECT id, relationcode, email_address, firstname, latname, last_contact_date
        FROM RELATIONS
        CROSS JOIN (SELECT @seq:=0, @relationcode := '', @email_address :='') Sub1
        ORDER BY relationcode, email_address, last_contact_date DESC
    ) Sub2
) Sub3
WHERE seq = 1

这使用子查询初始化变量。如果关系代码和电子邮件地址与前一行相同,则添加序列号,如果不是,则将它们重置为1并存储在字段中。然后外部选择检查序列号(作为字段,而不是变量名称),并且仅在记录为1时返回记录。

请注意,我已将此作为多个子查询完成。部分是为了让你更清楚,但也试图强制MySQL执行它的顺序。关于MySQL如何命令执行可能导致问题的事情,有几个可能的问题。他们从来没有为我做过,但是我希望通过子查询强制命令。

答案 1 :(得分:1)

这是一种适用于MySQL和Oracle的方法。它将问题重新描述为:从relations获取关系代码不大last_contact_date的所有行。

它的工作原理如下:

select r.*
from relations r
where not exists (select 1
                  from relations r2
                  where r2.relationcode = r.relationcode and
                        r2.last_contact_date > r.last_contact_date
                 );

使用适当的索引,这在两个数据库中应该非常有效。

注意:这假设last_contact_date存储为日期而非字符串(如表格示例中所示)。将日期存储为字符串只是一个非常糟糕的主意,您应该修复数据结构