MySQL查询有效地返回不包括重复信息的组合行

Posted

技术标签:

【中文标题】MySQL查询有效地返回不包括重复信息的组合行【英文标题】:MySQL query to efficiently return combined rows excluding duplicated info 【发布时间】:2020-10-20 03:01:14 【问题描述】:

所以这可能很简单,但我正在努力寻找一种有效的方法来做到这一点。我查看了许多其他问答,我已经搞砸了 DISTINCT、GROUP BY、子查询等。

我试图超级简化这个例子。 (出于示例的目的,没有 DB 规范化)这是一个 SQL 小提琴:

http://sqlfiddle.com/#!9/948be7c/1

CREATE TABLE IF NOT EXISTS `orders` (
  `id` int NOT NULL,
  `name` varchar(90) NULL,
  `email` varchar(200) NULL,
  `phone` varchar(200) NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;

INSERT INTO `orders` (`id`, `name`, `email`, `phone`) VALUES
  ('1', 'Bob', 'bob@email.com', NULL),
  ('2', 'Bobby', 'bob@email.com', '1115551111'),
  ('3', 'Robert', 'robert@email.com', '1115551111'),
  ('4', 'Fred', 'fred@email.com', '1115552222'),
  ('5', 'Freddy', 'fred@email.com', '1115553333')

如果我只是运行一个简单的选择,我会得到:

但我想对具有相同电子邮件地址或具有相同电话号码的任何结果“去重” - 因为他们将是同一个人,即使他们有多个 ID,即使他们他们的名字拼写不同。然后合并这些结果(“不同的”电子邮件地址之一和“不同的”电话号码之一以及姓名之一和 ID 之一。)

因此,对于上述内容,我最终会得到这样的结果:

有什么建议吗?

【问题讨论】:

什么决定了为重复返回哪个 id/name? 一开始为什么会有重复数据?您应该规范化您的数据库,以便所有客户信息都在另一个表的一行中,并且order 表具有customer 表的外键。 我尝试了 DISTINCT 和 GROUP BY 的多种变体,但没有得到我想要的。 (而且我的实际数据库要复杂得多,所以这些查询不相关。) 哪个 ID / 名字真的不重要。只需成为与电子邮件和电话匹配的其中之一即可。 您必须选择一组列作为分组依据。我认为没有任何方法可以按一组可变的列进行分组。 【参考方案1】:

我认为您可以通过使用相关子查询进行过滤来做您想做的事情:

select o.*
from orders o
where o.id = (
    select o1.id
    from orders o1
    where o1.email = o.email or o1.phone = o.phone
    order by o1.phone is not null desc, o1.email is not null desc, id
    limit 1
)

这仅保留具有相同phoneemail 的行中的一行,同时优先考虑phoneemail 不是null 的行。通过选择最低的id 打破平局。

对于您的示例数据,这将返回:

id  name    email           phone
2   Bobby   bob@email.com   1115551111
4   Fred    fred@email.com  1115552222

【讨论】:

我需要将它重构到我的场景中 - 但它似乎可以满足我的需要!我在 WHERE 子句中使用了很多它,但我不熟悉在 ORDER BY 中包含 IS NOT NULL 的能力 - 我必须对此进行一些阅读! @BeninCA 是的,order by 可以包含任何表达式,而不仅仅是列。请使用实际数量的记录尝试这种方法,并确保它能够充分满足您的需求【参考方案2】:

可以通过多种不同的方式来解释您的需求。

一种方法是将其重新定义为约束:仅在其中一个为真时才返回记录:

它有一个非空的电子邮件和电话,并且不存在具有相同电子邮件和电话且 ID 较低的记录 它有一个非空的email但为空的电话,并且没有相同的电子邮件和一个非空电话的记录,并且没有相同的电子邮件和一个空电话和较低的id的记录 它有一个非空电话但为空电子邮件,并且不存在相同电话和非空电子邮件的记录,并且不存在相同电话和空电子邮件和较低id的记录

这很容易转化为几个连接,不需要 group by 或 distinct。

【讨论】:

嗯。我认为您的建议将完成我所需要的。我没有想到“低身份”的概念。 当你说约束时——你的意思是作为 JOIN 上的 ON 语句的一部分还是使用 WHERE?

以上是关于MySQL查询有效地返回不包括重复信息的组合行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL系列- MySQL执行计划

Oracle高级查询

MySQL 查询联结表返回重复行

SQL 查询有效地选择不完美的重复项

如何有效地生成组合而不重复,它们之间有特定的数字

mysql查询优化之一: