Обновление первичного ключа MySQL

104

У меня есть таблица user_interactionsс 4 столбцами:

 user_1
 user_2
 type
 timestamp

Первичный ключ есть, (user_1,user_2,type)
и я хочу изменить его на(user_2,user_1,type)

Итак, я сделал следующее:

drop primary key ...  
add primary key (user_2,user_1,type)...

и вуаля ...

Проблема в том, что база данных находится на сервере.

Поэтому, прежде чем я смог обновить первичный ключ, уже закралось много дубликатов, и они постоянно появляются.

Что делать?

Что я хочу сделать сейчас, так это удалить дубликаты и оставить те, timestampкоторые находятся в самом последнем (столбец в таблице).

А потом как-нибудь еще раз обновить первичный ключ.

Simplefuzz
источник
16
Мне вдруг стало плохо из-за каждого администратора базы данных, который я проклял себе под нос ...
Игнасио Васкес-Абрамс,
5
в следующий раз добавьте уникальный ключ с теми же столбцами, что и первичный ключ, затем обновите первичный ключ
knittl
1
@Ignacio, он находится на сервере, но это резервный сервер :-). Я не администратор баз данных, но я не буду пробовать эту штуку на ДЕЙСТВИТЕЛЬНО живом сервере :-)
simplefuzz
1
@knittl, да, я так подумал сейчас, правда, очень поздно :-)
simplefuzz
4
@pixeline: это составной первичный ключ.
Игнасио Васкес-Абрамс,

Ответы:

233

В следующий раз используйте один оператор «alter table» для обновления первичного ключа.

alter table xx drop primary key, add primary key(k1, k2, k3);

Чтобы исправить ситуацию:

create table fixit (user_2, user_1, type, timestamp, n, primary key( user_2, user_1, type) );
lock table fixit write, user_interactions u write, user_interactions write;

insert into fixit 
select user_2, user_1, type, max(timestamp), count(*) n from user_interactions u 
group by user_2, user_1, type
having n > 1;

delete u from user_interactions u, fixit 
where fixit.user_2 = u.user_2 
  and fixit.user_1 = u.user_1 
  and fixit.type = u.type 
  and fixit.timestamp != u.timestamp;

alter table user_interactions add primary key (user_2, user_1, type );

unlock tables;

Блокировка должна прекратить поступать дальнейшие обновления, пока вы это делаете. Сколько времени это займет, очевидно, зависит от размера вашего стола.

Основная проблема в том, что у вас есть дубликаты с одинаковой меткой времени.

Мартин
источник
11

Если первичный ключ является значением auto_increment, вам необходимо удалить автоматическое приращение, затем отбросить первичный ключ, а затем повторно добавить автоматическое приращение

ALTER TABLE `xx`
MODIFY `auto_increment_field` INT, 
DROP PRIMARY KEY, 
ADD PRIMARY KEY (new_primary_key);

затем добавьте обратно автоматическое приращение

ALTER TABLE `xx` ADD INDEX `auto_increment_field` (auto_increment_field),
MODIFY `auto_increment_field` int auto_increment;

затем установите автоматическое приращение обратно к предыдущему значению

ALTER TABLE `xx` AUTO_INCREMENT = 5;
Frazras
источник
2

Вы также можете использовать IGNOREключевое слово, например:

 update IGNORE table set primary_field = 'value'...............
Сарфраз
источник