Увеличение количества ТОЛЬКО для дубликатов в MySQL - PullRequest
0 голосов
/ 07 мая 2020

Вот моя MySQL таблица. Я обновил вопрос, добавив к нему столбец 'id' (как указано в комментариях других).

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

Я следил за этим ответом и нашел код ниже. Но следующий код также добавляет счетчик «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

Ответы [ 4 ]

1 голос
/ 07 мая 2020

Если вы используете 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, это undefined, какая запись фактически получит каждое число.

0 голосов
/ 07 мая 2020

Если вы хотите иметь старый "порядок" старой таблицы, вам нужно гораздо больше кода

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
data_id | IF (row_num = 1 AND cntid = 1, NULL,row_num)
------: | -------------------------------------------:
   1232 |                                            1
   1232 |                                            2
   2031 |                                         <em>null</em>
   2355 |                                            1
   2355 |                                            2
   2355 |                                            3
   4562 |                                         <em>null</em>
   9867 |                                         <em>null</em>

db <> fiddle здесь

0 голосов
/ 07 мая 2020

Я предполагаю, что id - это столбец, который определяет порядок строк.

В MySQL 8 вы можете использовать row_number(), чтобы получить количество каждого data_id и CASE с EXISTS, чтобы исключить строки, у которых нет дубликатов.

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. С помощью EXISTS в предложении HAVING вы можете исключить строки, у которых нет дубликатов.

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

0 голосов
/ 07 мая 2020

Присоединитесь к запросу, который возвращает количество дубликатов.

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
...