【问题标题】:Incrementing count ONLY for duplicates in MySQL仅对 MySQL 中的重复项增加计数
【发布时间】:2020-08-22 00:33:47
【问题描述】:

这是我的 MySQL 表。我通过向其添加“id”列来更新问题(按照其他人在 cmets 中的说明)。

id    data_id

1     2355
2     2031
3     1232
4     9867
5     2355
6     4562
7     1232
8     2355

我想添加一个名为row_num 的新列,以便为重复项分配一个递增的数字,如下所示。结果的顺序无关紧要。

id    data_id     row_num
3     1232        1
7     1232        2
2     2031        null
1     2355        1
5     2355        2
8     2355        3
6     4562        null
4     9867        null

我关注了this 的回答并想出了下面的代码。但是下面的代码也为非重复值添加了一个计数'1',我该如何修改下面的代码以只为重复添加一个计数?

select data_id,row_num
from (
      select data_id,
             @row:=if(@prev=data_id,@row,0) + 1 as row_num,
             @prev:=data_id
        from my_table
)t

【问题讨论】:

  • 你运行的是哪个版本的 MySQL?
  • MySQL 5.6 版

标签: mysql sql count duplicates window-functions


【解决方案1】:

加入一个返回重复数的查询。

select t1.data_id, IF(t2.dups > 1, row_num, '') AS row_num
from (
      select data_id,
             @row:=if(@prev=data_id,@row,0) + 1 as row_num,
             @prev:=data_id
        from my_table
        order by data_id
) AS t1
join (
    select data_id, COUNT(*) AS dups
    FROM my_table
    GROUP BY data_id
) AS t2 ON t1.data_id = t2.data_id

【讨论】:

  • 它不增加计数,每个重复值的计数为'1'
【解决方案2】:

如果您正在运行 MySQL 8.0,则仅使用窗口函数可以更有效地执行此操作:

select
    data_id,
    case when count(*) over(partition by data_id) > 1
        then row_number() over(partition by data_id order by data_id) row_num
    end
from mytable

当窗口计数返回大于1时,你知道当前data_id有重复,此时你可以使用row_number()来分配递增的数字。

请注意,如果没有排序列来唯一标识共享同一 data_id 的组中的每条记录,则未定义哪个记录将实际获取每个编号。

【讨论】:

  • 关于ID列重要性的解释非常有用,我通过添加ID列更新了问题。
【解决方案3】:

我假设id 是定义行顺序的列。

在 MySQL 8 中,您可以使用 row_number() 获取每个 data_id 的数量,并使用 CASEEXISTS 排除没有重复的行。

SELECT t1.data_id,
       CASE 
         WHEN EXISTS (SELECT *
                             FROM my_table t2
                             WHERE t2.data_id = t1.data_id
                                   AND t2.id <> t1.id) THEN
           row_number() OVER (PARTITION BY t1.data_id
                              ORDER BY t1.id)
       END row_num
       FROM my_table t1;

在旧版本中,您可以使用子查询计算具有相同 data_id 但较小 id 的行。在HAVING 子句中使用EXISTS,您可以排除没有重复的行。

SELECT t1.data_id,
       (SELECT count(*)
               FROM my_table t2
               WHERE t2.data_id = t1.data_id
                     AND t2.id < t1.id
               HAVING EXISTS (SELECT *
                                     FROM my_table t2
                                     WHERE t2.data_id = t1.data_id
                                           AND t2.id <> t1.id)) + 1 row_num
      FROM my_table t1;

db<>fiddle

【讨论】:

  • 重复集合的第一个值没有得到数字。例如。当有 3 个重复项时,只有最后两个值计为 1 和 2
  • 第二个代码示例解决了我的问题。如果您能详细解释一下这段代码的工作原理,将会很有用。
【解决方案4】:

如果你想拥有旧表的旧“顺序”,你需要更多的代码

SELECT 
    data_id, IF (row_num = 1 AND cntid = 1, NULL,row_num) 
FROM
    (SELECT 
        @row:=IF(@prev = t1.data_id, @row, 0) + 1 AS row_num,
        cntid,
            @prev:=t1.data_id data_id
    FROM
        (SELECT 
        *
    FROM
       my_table
    ORDER BY data_id) t1 
    INNER JOIN (SELECT Count(*) cntid,data_id FROM my_table GROUP BY data_id)t2 
     ON t1.data_id = t2.data_id) t2
数据ID | IF (row_num = 1 AND cntid = 1, NULL,row_num) ------: | -------------------------------------------------------: 第1232章1 第1232章2 2031 | 第2355章1 第2355章2 第2355章3 4562 | 9867 |

db小提琴here

【讨论】:

  • 这不是还在非重复值上增加了“1”的计数吗?我需要摆脱非重复行上的计数“1”吗?请参阅问题中的预期结果表。
  • 好的,删除所有计数等于 1 的文件
猜你喜欢
  • 2021-12-25
  • 1970-01-01
  • 2018-03-15
  • 2021-03-24
  • 2021-12-30
  • 1970-01-01
  • 2021-02-09
  • 2020-09-07
  • 2021-04-02
相关资源
最近更新 更多