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的解决方案都将带回多条记录,如果同一关系代码/电子邮件地址恰好有两条记录,它们共享相同的最后联系日期。第二种解决方案确实避免了这个问题。