mysql - 如何在 MySQL 中选择重复行的第一个(但重复数据位于不同列中)

标签 mysql sql duplicates subquery

这是“查找第一个重复行”问题的变体,但是对于人类来说,使用常识显然是重复的行,但不是 MySQL 定义的重复行。

下表显示了组织成员应付款。 每行保存成员数据,如果它们的伙伴也是联合成员,则它们的联合数据相​​同,否则这些列为空或空字符串。 该表当前按member_name、member_ID 排序。

所有成员都出现在成员列中,因此,如果成员/联合元组出现在一行中,它最终会在其他地方“重复”出现,但成员和联合字段相反。

具体出现的位置取决于关节名称的字母顺序。

该表源自其他地方用于其他目的,因此当我获得它时我无法控制它的结构。例如

表 payment_due :

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 member_name, member_ID 时,我将“first”定义为序列中较早的位置)。

理想情况下,我想要两个查询,一个返回两个反向对中的第一个,一个返回最后一个,以便可以按成员名称的字母顺序生成报告,无论我们是否认为“名称”是该成员的名称。成员或其联合成员(见下文)。

期望的结果

查询 1 结果(使用第一个联合出现)

表 payment_due

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 结果(使用最后一次联合出现)

表 payment_due

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 结构,但我不知道如何在数据被复制时将反转行定义为“重复”出现在不同的列中(代码如下)。

这里有一个db-fiddle 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”)”,并且接受的答案没有解决两个不同列中的重复数据。

最佳答案

我想您应该能够使用具有 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

关于mysql - 如何在 MySQL 中选择重复行的第一个(但重复数据位于不同列中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54843627/

相关文章:

PHP MySQL 和队列、表锁定、读写器问题

java - 我的 jsp 页面未使用结果集 rs=st.executeQuery(); 进行验证

PHP/MySql - 从两个不同表检索数据的正确语法是什么?

sql - 向数据库表添加外键的指南 - Oracle

PHP MySQL 在同一个表中复制一行......使用主键和唯一键

exception - 域类的Grails软件包更改导致DuplicateMappingException

php - 如果数据库不存在,如何使用 PHP 创建数据库?

c# - NHibernate QueryOver - 结果太多的集合

mysql - 澄清 InnoDB 引擎中的行级锁和 MySQL 数据库中 MyISAM 引擎中的表级锁的区别

arrays - 二维数组中的前 N ​​个值,要屏蔽重复项