【问题标题】:MySQL : Find duplicate records but EXCLUDE the first one from the listMySQL:查找重复记录但从列表中排除第一个记录
【发布时间】:2020-07-06 05:37:16
【问题描述】:

我有一张下表:

MariaDB [groupdb]> select * from album;    
+----+---------+---------+
| id | artist  | user_id |
+----+---------+---------+
|  1 | ArtistX |   45677 |
|  2 | ArtistY |  378798 |
|  3 | ArtistX |   45677 |
|  4 | ArtistZ |  123456 |
|  5 | ArtistY |  888888 |
|  6 | ArtistX |    2312 |
|  7 | ArtistY |  378798 |
|  8 | ArtistY |  888888 |
|  9 | ArtistY |  888888 |
+----+---------+---------+
9 rows in set (0.000 sec)

我尝试使用以下查询查找重复记录:

MariaDB [groupdb]> select * from album where artist IN (select artist from album group by artist having count(artist)>1) and user_id IN (select user_id from album group by user_id having count(user_id)>1);
+----+---------+---------+
| id | artist  | user_id |
+----+---------+---------+
|  1 | ArtistX |   45677 |
|  2 | ArtistY |  378798 |
|  3 | ArtistX |   45677 |
|  5 | ArtistY |  888888 |
|  7 | ArtistY |  378798 |
|  8 | ArtistY |  888888 |
|  9 | ArtistY |  888888 |
+----+---------+---------+
7 rows in set (0.001 sec)    

这一切都很好。虽然我希望我的结果集有一个重复列表,但不包括第一个。即类似于下面的。
预期输出

+----+---------+---------+
| id | artist  | user_id |
+----+---------+---------+
|  3 | ArtistX |   45677 |
|  7 | ArtistY |  378798 |
|  8 | ArtistY |  888888 |
|  9 | ArtistY |  888888 |
+----+---------+---------+

正如您在上面看到的,这是一个重复列表,不包括第一个。

注意:若要复制记录,artistuser_id 必须相同。
我的挑战是提出一个导致上述结果集的查询。

【问题讨论】:

  • 执行 GROUP BY,使用 HAVING 和 MAX()。

标签: mysql sql duplicates


【解决方案1】:

这在支持ROW_NUMBER 的最新版本的 MariaDB 中很容易处理:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY artist, user_id ORDER BY id) rn
    FROM album
)

SELECT id, artist, user_id
FROM cte
WHERE rn > 1;

上面查询中使用的中间 CTE 如下所示:

+----+---------+---------+----+
| id | artist  | user_id | rn |
+----+---------+---------+----+
|  1 | ArtistX |   45677 | 1  |
|  2 | ArtistY |  378798 | 1  |
|  3 | ArtistX |   45677 | 2  |
|  4 | ArtistZ |  123456 | 1  |
|  5 | ArtistY |  888888 | 1  |
|  6 | ArtistX |    2312 | 1  |
|  7 | ArtistY |  378798 | 2  |
|  8 | ArtistY |  888888 | 2  |
|  9 | ArtistY |  888888 | 3  |
+----+---------+---------+----+

请注意,没有重复的艺术家/用户 ID 对只会被分配一个行号 1,因此永远不会保留在输出中。

【讨论】:

  • 感谢您的回答。它工作正常。是否可以在不依赖查询中的 id 的情况下实现相同的目标?我尝试将 ORDER BY 更改为 ORDER BY artist 之类的其他名称,但现在 id 已关闭。
  • 根据您的示例数据,id 列决定了哪些重复项是第一个还是最后一个。代替id,您可以使用任何也可以表示此订单的列。
【解决方案2】:

您可以使用row_number() 为每个艺术家/用户 ID 获取一行:

select a.*
from (select a.*,
             row_number() over (partition by artist, user_id order by id) as seqnum
      from album a
     ) a
where seqnum > 1;

在旧版本中,您可以使用:

select a.*
from album a
where a.id > (select min(a2.id)
              from album a2
              where a2.artist = a.artist and a2.user_id = a.user_id
             );

【讨论】:

    【解决方案3】:

    您希望选择所有存在具有较小 ID 的同级的行。我认为最简单的表达方式是:

    select * 
    from album a
    where exists
    (
      select * 
      from album a2
      where a2.artist = a.artist
      and a2.user_id = a.user_id
      and a2.id < a.id
    )
    order by id;
    

    【讨论】:

      【解决方案4】:

      MariaDB 10.3 及更高版本支持except 功能,所以你可以简单地做

      select id, artist, user_id
      from t
      except 
      select min(id), artist, user_id
      from t
      group by artist, user_id;
      

      如果这不是一个选项,您可以使用not in

      select id, artist, user_id
      from t
      where (id, artist, user_id) not in (select min(id), artist, user_id
                                          from t
                                          group by artist, user_id);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-18
        • 2019-03-28
        • 1970-01-01
        • 2010-10-25
        • 1970-01-01
        • 2018-02-17
        相关资源
        最近更新 更多