MySQL 高效查询 return 合并行,排除重复信息
MySQL query to efficiently return combined rows excluding duplicated info
所以这可能很简单,但我竭尽全力想找出一种有效的方法来做到这一点。我看了很多其他的问答,我搞砸了 DISTINCT、GROUP BY、子查询等。
我试图超级简化这个例子。 (为了示例的目的,没有数据库规范化)这是一个 SQL fiddle:
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')
如果我只是 运行 一个简单的 select,我会得到:
但我想“删除重复”任何具有相同电子邮件地址或相同 phone 号码的结果 - 因为他们将是同一个人,即使有多个 ID对他们来说,即使他们的名字拼写不同。然后合并这些结果(“不同”电子邮件地址之一和“不同”phone 号码之一以及其中一个姓名和一个 ID。)
所以对于上面的内容,我最终会得到这样的结果:
有什么建议吗?
可以通过多种不同方式解释您的要求。
一种方法是将其重新构造为约束:只有 return 一条记录,如果其中一个为真:
- 它有一个非空的电子邮件和 phone,并且不存在具有相同电子邮件和 phone 以及较低 ID
的记录
- 它有一个非空的电子邮件但为空 phone,并且不存在具有相同电子邮件和非空的记录 phone,并且不存在具有相同电子邮件和空的记录phone 和一个较低的 id
- 它有一个非空 phone 但电子邮件为空,并且不存在具有相同 phone 和非空电子邮件的记录,并且不存在具有相同 [=24= 的记录] 和一个空电子邮件和一个较低的 id
这很容易转化为几个连接,不需要分组依据或不同。
我认为您可以通过使用相关子查询进行过滤来做您想做的事情:
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
)
这只保留具有相同 phone
或 email
的行中的一行,同时优先考虑 phone
和 email
不是 null
。通过选择最低的 id
.
来打破平局
对于您的样本数据,returns:
id name email phone
2 Bobby bob@email.com 1115551111
4 Fred fred@email.com 1115552222
所以这可能很简单,但我竭尽全力想找出一种有效的方法来做到这一点。我看了很多其他的问答,我搞砸了 DISTINCT、GROUP BY、子查询等。
我试图超级简化这个例子。 (为了示例的目的,没有数据库规范化)这是一个 SQL fiddle:
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')
如果我只是 运行 一个简单的 select,我会得到:
但我想“删除重复”任何具有相同电子邮件地址或相同 phone 号码的结果 - 因为他们将是同一个人,即使有多个 ID对他们来说,即使他们的名字拼写不同。然后合并这些结果(“不同”电子邮件地址之一和“不同”phone 号码之一以及其中一个姓名和一个 ID。)
所以对于上面的内容,我最终会得到这样的结果:
有什么建议吗?
可以通过多种不同方式解释您的要求。
一种方法是将其重新构造为约束:只有 return 一条记录,如果其中一个为真:
- 它有一个非空的电子邮件和 phone,并且不存在具有相同电子邮件和 phone 以及较低 ID 的记录
- 它有一个非空的电子邮件但为空 phone,并且不存在具有相同电子邮件和非空的记录 phone,并且不存在具有相同电子邮件和空的记录phone 和一个较低的 id
- 它有一个非空 phone 但电子邮件为空,并且不存在具有相同 phone 和非空电子邮件的记录,并且不存在具有相同 [=24= 的记录] 和一个空电子邮件和一个较低的 id
这很容易转化为几个连接,不需要分组依据或不同。
我认为您可以通过使用相关子查询进行过滤来做您想做的事情:
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
)
这只保留具有相同 phone
或 email
的行中的一行,同时优先考虑 phone
和 email
不是 null
。通过选择最低的 id
.
对于您的样本数据,returns:
id name email phone
2 Bobby bob@email.com 1115551111
4 Fred fred@email.com 1115552222