这是“先查找重复行”问题的一种变体,但其中的行显然是使用人类的常识对人类重复的,但不是MySQL定义的重复行。
我有一张下表,该表代表应收组织会员的款项。 每行都保存成员数据,并且如果其伙伴也是联合成员,则包含其联合的相同数据,否则,这些列为null或空字符串。 该表当前是按member_name,member_ID排序的。
所有成员显示在成员列中,因此,如果成员/联合元组显示在一行中,则最终将在其他位置出现“重复”,但成员和联合字段相反。
出现的确切位置取决于关节名称的字母顺序。
该表源自其他地方,因此有其他用途,因此我无法控制它的结构。例如
表格付款到期日:
member_id | member_name | member_payment | joint_id | joint_name | joint_payment
==========|=============|================|==========|============|=============
11 | ARNOLD | 40 | (NULL) | | (NULL)
22 | BAKER | 36 | 88 | ELNET | 35
33 | COOPER | 30 | 44 | COOPER | 30
44 | COOPER | 30 | 33 | COOPER | 30
55 | DAVIS | 40 | (NULL) | | (NULL)
88 | ELNET | 35 | 22 | BAKER | 36
66 | FRENCH | 37 | 99 | JOYCE | 50
77 | GRANT | 45 | (NULL) | | (NULL)
99 | JOYCE | 50 | 66 | FRENCH | 37
100 | LAWSON | 46 | (NULL) | | (NULL)
请有人帮我设计一个查询,该查询将显示所有包含非联合成员的行,仅显示联合关系的第一行,即不显示重复/反向行。
(当原始表应用ORDER BY成员名,成员ID时,我将“第一”定义为序列中的更早位置。)
理想情况下,我想进行两个查询,一个返回两个反向对中的第一个,另一个返回最后一对对,以便无论我们是否认为“名称”是成员名称的字母顺序,都可以按字母顺序生成报告。成员或他们的关节(见下文)。
所需结果
查询1个结果(使用第一个联合出现)
表格付款到期
member_id | member_name | member_payment | joint_id | joint_name | joint_payment
==========|=============|================|==========|============|=============
11 | ARNOLD | 40 | (NULL) | | (NULL)
22 | BAKER | 36 | 88 | ELNET | 35
33 | COOPER | 30 | 44 | COOPER | 30
55 | DAVIS | 40 | (NULL) | | (NULL)
66 | FRENCH | 37 | 100 | JOYCE | 50
77 | GRANT | 45 | (NULL) | | (NULL)
100 | LAWSON | 46 | (NULL) | | (NULL)
(ie member_id's 44, 88, 100 not shown)
或查询2结果(使用最后一个联合出现)
表格付款到期
member_id | member_name | member_payment | joint_id | joint_name | joint_payment
==========|=============|================|==========|============|=============
11 | ARNOLD | 40 | (NULL) | | (NULL)
44 | COOPER | 30 | 33 | COOPER | 30
55 | DAVIS | 40 | (NULL) | | (NULL)
88 | ELNET | 35 | 22 | BAKER | 36
77 | GRANT | 45 | (NULL) | | (NULL)
99 | JOYCE | 50 | 66 | FRENCH | 37
100 | LAWSON | 46 | (NULL) | | (NULL)
(ie member_id's 22, 33, 66 not shown)
我尝试过的事情
我一直在添加一个递增的列,并执行非联接与通常的“重复行的第一个” SQL结构的合并,但是当复制数据时,我看不到如何将反向行定义为“重复项”出现在不同的列中(到目前为止,下面的代码)。
这里有一个小提琴https://www.db-fiddle.com/f/f7DoySyi8boDG3DxMpcD86/0
(我使用DB-Fiddle是因为SQLfiddle目前似乎有问题,至少对我而言)
代码已尝试
-- make a temp table with an extra column holding a unique identifier 'orderby'
SET @x:=0;
CREATE TEMPORARY TABLE payment_due_2 AS
(SELECT
@x:=@x+1 AS orderby,
payment_due.*
FROM payment_due);
-- make a copy of the temp table to avoid problems with reopening temp tables
CREATE TEMPORARY TABLE payment_due_3 AS
(SELECT * FROM payment_due_2);
-- make a second copy of the temp table for the same reason
CREATE TEMPORARY TABLE payment_due_4 AS
(SELECT * FROM payment_due_2);
SELECT * FROM
(
SELECT payment_due_4.* -- get all the non joints
FROM payment_due_4
WHERE joint_id IS NULL
UNION
SELECT payment_due_2.* -- get the first of the 'duplicates'
FROM payment_due_2
JOIN
(SELECT MIN(orderby) AS min_id
FROM payment_due_3
GROUP BY payment_due_3.member_id
) AS T3
ON payment_due_2.orderby = T3.min_id
) as T5
ORDER BY member_name, member_id;
我看着this SO question似乎是我的复制品,但我不太清楚。正如另一个SO用户所说,这是因为“它指定了两个不同的内容(查找重复项,将标志设置为'Y')”,并且接受的答案未解决位于两个不同列中的重复数据。
答案 0 :(得分:1)
我想您应该可以使用具有EXISTS条件的相关子查询来过滤掉不必要的重复项。
此查询将保留具有最小member_id的重复项(并且也记录不包含joint_id的记录):
SELECT *
FROM payment_due p
WHERE NOT EXISTS (
SELECT 1
FROM payment_due p1
WHERE
p1.member_id = p.joint_id
AND p1.joint_id = p.member_id
AND p1.member_id < p.member_id
)
要获取具有最高member_id的副本,只需更改子查询中的最后一个条件即可:
AND p1.member_id > p.member_id