Проверьте наличие дубликатов в базе данных и удалите их - PullRequest
3 голосов
/ 15 декабря 2010

У меня есть таблица, структурированная следующим образом:

table(A, B)

Они оба являются первичными ключами, и они необходимы для соединения двух записей в другой таблице (т.е. они символизируют дружбу между пользователями).

Мне нужно проверить таблицу и, если (A, B) существует, удалить возможный (B, A) (или наоборот). Поскольку база данных огромна, я не могу делать это вручную для каждой записи каждый раз.

Конечно, я запрограммировал скрипт, который заполнил базу данных, чтобы проверить эту ситуацию и избежать ее, но мыЭтот сценарий использовался на 8 разных компьютерах, поэтому у разных дампов могут быть «обратные дубликаты».

1 Ответ

1 голос
/ 15 декабря 2010

Проблема возникла потому, что отношения, которые вы пытаетесь описать, симметричны - но схема моделирует асимметричную связь. Право смоделировать проблему будет состоять в том, чтобы вести таблицу отношений, а затем иметь таблицу, связывающую пользователей с отношениями, например,

relationship:
   id auto_increment

related:
   r_id foreign key references relationship.id
   u_id foreign key references user.id
   primary key (r_id, u_id)

Но для очистки существующих данных ... очевидный подход был бы ...

DELETE FROM yourtable d
WHERE A>B AND EXISTS (
    SELECT 1 
    FROM yourtable r
    WHERE r.A=d.B
    AND r.B =d.A
)

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

SELECT d.A,d.B 
INTO dups
FROM yourtable d, yourtable r
WHERE d.A>d.B
AND r.A=d.B
AND r.B =d.A;

тогда ....

DELETE FROM yourtable
WHERE EXISTS (
 SELECT 1 FROM dups
 WHERE dups.A=yourtable.A
 AND dups.B=yourtable.B
)

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

DELETE FROM yourtable
WHERE CONCAT(A, '/', B) IN (
 SELECT CONCAT(A, '/' B) FROM dups
)
...