Mysql在单个查询中消除重复记录

Mysql在单个查询中消除重复记录,mysql,sql,deduplication,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_c

我有下表:

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`)
)
此表中有重复项,它们与完全相同的关系代码和电子邮件地址有关。他们可以在那里呆两次甚至十次。 我需要一个查询来选择所有记录的id,但多次排除其中的记录。在这些记录中,我只想选择具有最近一次联系人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中,在一个查询中可以做同样的事情。
有什么想法吗?

通常的做法是通过子查询获取最新记录,然后将其与表连接起来:-

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说它可能会命令执行可能导致问题的事情,这可能有几个问题。他们从来没有为我做过,但我希望通过子查询强制执行订单。

通常的做法是通过子查询获取最新记录,然后将其与表连接起来:-

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说它可能会命令执行可能导致问题的事情,这可能有几个问题。他们从来没有为我做过,但是我希望通过子查询来强制执行命令。

这里有一个方法可以在MySQL和Oracle中使用。它将问题重新表述为:从
relations
中获取所有行,其中relationcode没有更大的
last\u contact\u 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\u contact\u date
存储为日期,而不是字符串(如表示例中所示)。将日期存储为字符串是一个非常糟糕的主意,您应该修复数据结构。这里有一种方法可以在MySQL和Oracle中使用。它将问题重新表述为:从
relations
中获取所有行,其中relationcode没有更大的
last\u contact\u 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\u contact\u date
存储为日期,而不是字符串(如表示例中所示)。将日期存储为字符串是一个非常糟糕的主意,您应该修复您的数据结构

谢谢,很好的构造,通过此查询,我能够以良好的性能(创建一些索引后)获得所需的结果。谢谢,很好的构造,我能够以良好的性能(创建一些索引后)获得所需的结果感谢您的解释,这也是一个有趣的解决方案,但最后我还是想从Gordon那里得到一个更简单的查询。根据您处理的记录数量,哪个更快可能会有很大的不同。就我个人而言,我尽量避免相关的子查询,除非是在有限的情况下。我的第二种方法不是我通常使用的方法,除非在极少数情况下。例如,我的第一个解决方案和Gordons的解决方案都将带回多条记录,如果同一关系代码/电子邮件地址恰好有两条记录,它们共享相同的最后联系日期。第二个解决方案确实避免了这个问题。感谢您的解释,这也是一个有趣的解决方案,但最后我还是想从Gordon那里得到一个更简单的查询。根据您处理的记录数量,哪个更快可能会有很大的不同。就我个人而言,我尽量避免相关的子查询,除非是在有限的情况下。我的第二种方法不是我通常使用的方法,除非在极少数情况下。例如,我的第一个解决方案和Gordons的解决方案都将带回多条记录,如果同一关系代码/电子邮件地址恰好有两条记录,它们共享相同的最后联系日期。第二种解决方案确实避免了这个问题。