从不同的相关记录组中选择两列之一中包含重复值的所有行
Posted
技术标签:
【中文标题】从不同的相关记录组中选择两列之一中包含重复值的所有行【英文标题】:Select all rows containing duplicate values in one of two columns from within distinct groups of related records 【发布时间】:2012-05-13 00:45:44 【问题描述】:我正在尝试创建一个 mysql 查询,该查询将返回包含一组相关记录中重复值的所有单个行(未分组)。 “相关记录组”是指具有相同帐号的那些(根据下面的示例)。
基本上,在共享相同不同帐号的每组相关记录中,只选择那些其date
或amount
列的值与该帐户记录组中另一行的值相同的行。仅应将值视为该帐户组中的重复值。下面的示例表和理想的输出详细信息应该可以清楚地说明问题。
另外,我不关心返回状态为 X 的任何记录,即使它们具有重复值。
相关数据的小样本表:
id account invoice date amount status
1 1 1 2012-04-01 0 X
2 1 2 2012-04-01 120 P
3 1 2 2012-05-01 120 U
4 1 3 2012-05-01 117 U
5 2 4 2012-04-01 82 X
6 2 4 2012-05-01 82 U
7 2 5 2012-03-01 81 P
8 2 6 2012-05-01 80 U
9 3 7 2012-03-01 80 P
10 3 8 2012-04-01 79 U
11 3 9 2012-04-01 78 U
从所需 SQL 查询返回的理想输出:
id account invoice date amount status
2 1 2 2012-04-01 120 P
3 1 2 2012-05-01 120 U
4 1 3 2012-05-01 117 U
6 2 4 2012-05-01 82 U
8 2 6 2012-05-01 80 U
10 3 8 2012-04-01 79 U
11 3 9 2012-04-01 78 U
因此,不应同时返回第 7/9 行和第 8/9 行,因为它们的重复值在各自帐户范围内不被视为重复值。但是,应该返回第 8 行,因为它与第 6 行共享一个重复值。
稍后,我可能希望通过仅抓取具有匹配状态的重复行来进一步完善选择,因此将排除第 2 行,因为它与在该帐户的记录组中找到的其他两个不匹配。这会使查询变得更加困难吗?是否只是添加 WHERE 或 HAVING 子句的问题,还是比这更复杂?
我希望我对我要完成的工作的解释是有意义的。我尝试过使用 INNER JOIN ,但这会多次返回每个所需的行。我不想要重复的重复。
表结构和样本值:
CREATE TABLE payment (
id int(11) NOT NULL auto_increment,
account int(10) NOT NULL default '0',
invoice int(10) NOT NULL default '0',
date date NOT NULL default '0000-00-00',
amount int(10) NOT NULL default '0',
status char(1) NOT NULL default '',
PRIMARY KEY (id)
);
INSERT INTO payment VALUES (1, 1, 1, '2012-04-01', 0, 'X');
INSERT INTO payment VALUES (2, 1, 2, '2012-04-01', 120, 'P');
INSERT INTO payment VALUES (3, 1, 2, '2012-05-01', 120, 'U');
INSERT INTO payment VALUES (4, 1, 3, '2012-05-01', 117, 'U');
INSERT INTO payment VALUES (5, 2, 4, '2012-04-01', 82, 'X');
INSERT INTO payment VALUES (6, 2, 4, '2012-05-01', 82, 'U');
INSERT INTO payment VALUES (7, 2, 5, '2012-03-01', 81, 'p');
INSERT INTO payment VALUES (8, 2, 6, '2012-05-01', 80, 'U');
INSERT INTO payment VALUES (9, 3, 7, '2012-03-01', 80, 'U');
INSERT INTO payment VALUES (10, 3, 8, '2012-04-01', 79, 'U');
INSERT INTO payment VALUES (11, 3, 9, '2012-04-01', 78, 'U');
【问题讨论】:
能不能把你的sql表结构放上来 没问题,老板。上面加了!还在其下方添加了示例值。 :) 为什么输出中不包含id
1 的行?其日期与其帐户组中的另一个日期相匹配。
为什么不是 7/9 8/9?他们在不同的帐户中...
我认为这是一个 WHERE 状态!= 'X'
【参考方案1】:
这种类型的查询可以实现为semi join。
半连接用于从连接中的一个表中选择行。
例如:
select distinct l.*
from payment l
inner join payment r
on
l.id != r.id and l.account = r.account and
(l.date = r.date or l.amount = r.amount)
where l.status != 'X' and r.status != 'X'
order by l.id asc;
注意distinct
的使用,并且我只从左表中选择列。这样可以确保没有重复。
连接条件检查:
它没有将一行加入到自身中 (l.id != r.id
)
行在同一个帐户中 (l.account = r.account
)
并且日期或金额相同 (l.date = r.date or l.amount = r.amount
)
对于问题的第二部分,您需要更新查询中的 on
子句。
【讨论】:
很好,现在唯一的问题是某些行出现乱序。通过ORDER BY id ASC
进行简单修复?
添加了 ORDER BY 后,您的第一个版本非常有用。现在这个版本由于某种原因无法返回第 10/11 行。
@purefusion 你确定吗?它在我的机器上返回它们。我只是复制并粘贴了您的create table
和inserts
,以及这个查询。
@purefusion 实际上我离开了TYPE=InnoDB AUTO_INCREMENT=11
,因为type = InnoDB
导致我的语法错误(5.5.11)。
嗯,我删除了表并使用上面的 CREATE/INSERT 代码重新创建了它,然后复制了您的查询并在该表上运行它。第一次它没有返回 10/11,但我第二次重新创建表时它工作得很好!奇怪的东西……【参考方案2】:
这似乎有效
select * from payment p1
join payment p2 on
(p1.id != p2.id
and p1.status != 'X'
and p1.account = p2.account
and (p1.amount = p2.amount or p1.date = p2.date))
group by p1.id
http://sqlfiddle.com/#!2/a50e9/3
【讨论】:
这会将所有列返回两次,并且也无法返回第 10/11 行。 :\ 它为 id 的 10 和 11 生成行。检查小提琴,并使用p1.*
是的,在重新创建表之后,现在可以在我的表上工作。一定是侥幸。好吧,我绝对很高兴看到另一种方法。谢谢! :)以上是关于从不同的相关记录组中选择两列之一中包含重复值的所有行的主要内容,如果未能解决你的问题,请参考以下文章