Как удалить повторяющиеся строки в этой (слегка) сложной ситуации с базой данных MySQL? - PullRequest
0 голосов
/ 23 января 2011

Хорошо. Пожалуйста, терпите меня, я сосу объяснения.

У меня есть база данных контактной информации, которая собирается через форму на веб-сайте. Очевидно, что люди нажимают кнопку «Отправить» несколько раз случайно (или специально, но исправление - это другая проблема), поэтому в этой базе данных МНОГО дублирующих строк.

Итак, таблица1 содержит контактную информацию как таковую:

ID  |  date  |  unique ID code  |  first name, blah blah
1      stuff    20110101ba78b      joe

И таблица2 содержит связанные данные, соединенные уникальным полем кода идентификатора, например:

ID  |  data  |  unique ID code
1      a        20110101ba78b
2      b        20110101ba78b

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

Итак, моя дилемма заключается в следующем: я знаю, что легко создать временную таблицу и выбрать SELECT DISTINCT (все поля), но я хочу сохранить поле уникального идентификатора как минимум для одной из дублированных строк. Если я сохраню поле уникального идентификатора, оно будет уникальным для каждой строки, даже если другие данные точно такие же, поэтому SELECT DISTINCT (все поля) не будет работать, он сохранит все строки. Надеюсь, я подробно объяснил это. Пожалуйста, попросите меня для получения дополнительной информации, если это необходимо.

РЕДАКТИРОВАТЬ: Я уверен, что я мог бы избавиться от поля идентификатора для каждой таблицы, но, насколько я понимаю, это просто ... там быть там.

Ответы [ 2 ]

1 голос
/ 23 января 2011

С первым уточнением и небольшим чтением между строками мы можем догадаться, что будет достаточно сохранить только первую или последнюю запись для данного «уникального идентификационного кода» в Таблице 1, где первый или последний означает самый старый или самый новый запись. Запросы одинаковы, за исключением MAX и MIN. Я предполагаю, что столбец «date» содержит достаточно точную (1 секунду или меньше) степень детализации, чтобы вы не получали один и тот же уникальный код идентификатора дважды за квант времени; вряд ли это имеет место, если столбец «date» действительно содержит только значение DATE (год, месяц, день), но, вероятно, имеет место, если у вас есть TIMESTAMP (3) и вполне может иметь место с TIMESTAMP.

Как всегда в SQL, постройте запрос поэтапно, красиво и аккуратно.

Найти самую новую запись для каждого уникального идентификационного кода с несколькими записями

SELECT Unique_ID_Code, MAX(date) AS Newest
  FROM Table1
 GROUP BY Unique_ID_Code
HAVING COUNT(*) > 1

Найти детали для уникального идентификационного кода, соответствующего новейшей записи

SELECT T1.*
  FROM Table1 AS T1
  JOIN (SELECT Unique_ID_Code, MAX(date) AS Newest
          FROM Table1
         GROUP BY Unique_ID_Code
        HAVING COUNT(*) > 1
       ) AS M
    ON M.Unique_ID_Code = T1.Unique_ID_Code AND M.Newest = T1.Date

Теперь хитрый материал

Что вы будете делать дальше, зависит от того, насколько вы доверяете поддержке транзакций в вашей СУБД и насколько велика таблица Table1, и от того, есть ли у вас ограничения ON DELETE CASCADE для ваших внешних ключей, и ...

Вы можете создать временную таблицу со строками, выбранными вторым запросом выше (я полагаю, синтаксис MySQL; другие СУБД используют для этого разные обозначения).

CREATE TEMPORARY TABLE KeepTheseRows
    SELECT T1.*
      FROM Table1 AS T1
      JOIN (SELECT Unique_ID_Code, MAX(date) AS Newest
              FROM Table1
             GROUP BY Unique_ID_Code
            HAVING COUNT(*) > 1
           ) AS M
        ON M.Unique_ID_Code = T1.Unique_ID_Code AND M.Newest = T1.Date;

затем удалите все строки из Таблицы1, которые совпадают с повторяющимися уникальными кодами идентификаторов:

DELETE FROM Table1
    WHERE Unique_ID_Code IN (SELECT Unique_ID_Code FROM KeepTheseRows);

и затем восстановить строки, которые нужно сохранить:

INSERT INTO Table
    SELECT * FROM KeepTheseRows;

Возможно, вам придется отложить проверку ограничений, пока это происходит, или вам может потребоваться удалить ограничения внешнего ключа, когда это происходит. Вам нужно беспокоиться об активности во время этой операции; было бы лучше, если бы люди не вставляли строки в Table1 во время работы. Если они изменяют таблицу при запуске, вы можете обнаружить, что вам придется выполнять обработку несколько раз. Вы должны добавить уникальное ограничение в Table1.Unique_ID_Code как можно скорее, чтобы вы больше не попали в беспорядок. (И не забудьте снова включить любые отложенные ограничения или воссоздать и удалить внешние ключи.)

Возможно, есть другие эквивалентные способы сделать это; это зависит только от стандартного (SQL-92) SQL, за исключением записи временной таблицы.

Поэкспериментируйте с копией вашей производственной базы данных.

0 голосов
/ 23 января 2011

Это позволяет обновить таблицу 2, чтобы использовать наименьший номер уникального идентификатора для идентичной контактной информации:

UPDATE Table2
SET Table2.uniqueID = (
    SELECT T1.UniqueID
    FROM Table1 T1, Table1 T2
    WHERE T1.unique ID &lt T2.unique ID
    AND T1.firstname = T2.firstname
    AND T1.date = T2.date
    AND T1.blah, blah = T2.blah, blah
) 
WHERE Table2.uniqueID = (
    Select T1.UniqueID
    from Table1 T1, CopyOfTable1 T2
    where T1.firstname = T2.firstname
    and T1.date = T2.date
    and T1.blah, blah = T2.blah, blah
);

Это для удаления всех, кроме ОДНОГО (с наименьшим уникальным ID) дубликата записей контактной информации:

delete T1
from Table1 T1, CopyOfTable1 T2
where T1.unique ID > T2.unique ID
and T1.firstname = T2.firstname
and T1.date = T2.date
and T1.blah, blah = T2.blah, blah
...