如何选择MySQL中重复的​​行的第一行(但是重复的数据在不同的列中)

时间:2019-02-23 16:30:17

标签: mysql sql duplicates

这是“先查找重复行”问题的一种变体,但其中的行显然是使用人类的常识对人类重复的,但不是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')”,并且接受的答案未解决位于两个不同列中的重复数据。

1 个答案:

答案 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