За последние 24 часа нас посетили 17743 программиста и 1619 роботов. Сейчас ищут 1877 программистов ...

Поиск двойных записей в базе данных

Тема в разделе "MySQL", создана пользователем S.I.G, 15 июл 2016.

  1. S.I.G

    S.I.G Новичок

    С нами с:
    19 апр 2016
    Сообщения:
    86
    Симпатии:
    0
    Здравствуйте форумчане, столкнулся с такой проблемой, что в моей базе данных раздвоились некоторые строки, какие я не знаю и искать их среди 200к строк очень напряжно. Нет ли какого-то способа быстро найти такие строки-клоны и удалить их?
     
  2. lastdays

    lastdays Активный пользователь

    С нами с:
    27 сен 2012
    Сообщения:
    410
    Симпатии:
    74
    Решение не ахти, но "прокатит". БЭкап стоит сделать, прежде чем удалять.

    PHP:
    1. $del = array();
    2. $data = $db->query("SELECT `id`, `uid`, count(1) as `count` FROM `test`  GROUP BY `uid`");
    3. if ( count ( $data ) )
    4. {
    5. foreach ( $data as $d )
    6. {
    7.   //- Если записей, больше чем 1
    8.   if ( $d["count"] > 1 )
    9.   {
    10.    $del[] = $d["id"];
    11.   }
    12. }
    13. unset( $data, $d );
    14.  
    15. //- Удаляем
    16. if ( count ( $del ) ) $db->query("DELETE FROM `test` WHERE `id` IN(".join(',',$del ).")",null);
    17. }
     
    S.I.G нравится это.
  3. S.I.G

    S.I.G Новичок

    С нами с:
    19 апр 2016
    Сообщения:
    86
    Симпатии:
    0
    Спасибо большое!:)
     
  4. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
    Не стоит благодарить. Это неудачная подсказка.

    1. Нельзя так делать: SELECT `id`, `uid` … GROUP BY `uid`— это логическая ошибка, значение `id` неопределено. А при некоторых настройках сервера mysql это вызовет синтаксическую ошибку.
    Можно например так: SELECT MIN(`id`) AS `id`, `uid` … GROUP BY `uid`
    2. Насколько я вижу, при count > 1 будет удаляться одна запись. То есть если у нас 10 повторов конкретного uid, их останется 9. А цель была избавиться от повторов. Задача не выполнена.

    Всё можно сделать в один sql-запрос без всяких циклов. http://ru.stackoverflow.com/a/425078/176610
     
    runcore и S.I.G нравится это.
  5. lastdays

    lastdays Активный пользователь

    С нами с:
    27 сен 2012
    Сообщения:
    410
    Симпатии:
    74
    Так ТС и написал, что "раздвоились" строки, а не их по 10 клонов.

    з.ы. а можно подробнее по первому пункту?
     
  6. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
    @lastdays

    про возможность ошибки с вылетом:
    http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by

    про логическую ошибку, даже если не вылетает:
    попробуй рассуждать логически. группировка это объединение нескольких строк в одну. если со значением группируемого (т.е. из фразы GROUP BY) поля всё понятно, то что должно быть на выходе в других полях?

    вот задачка "на пальцах":
    допустим есть школьный класс, в нём дети примерно одного возраста. вероятность повтора количества полных лет довольно велика.
    попробуем составить запрос для класса 1а:
    Код (Text):
    1. SELECT age, COUNT(*) AS cnt, first_name
    2. FROM pupils
    3. GROUP BY age
    4. WHERE class='1a'
    что именно должно получиться на выходе. допустим есть 30 учеников, из них 25-ти исполнилось 6, остальным 7. Что будет в поле first_name?
    Код (Text):
    1. age cnt first_name
    2. === === =========
    3.   6   25  Саша
    4.   7    5  Маша
    Это нормально? Не думаю! :) Почему там Саша, почему не Антон?

    а если добавить в GROUP BY еще одно поле: GROUP BY age, first_name, то логической ошибки уже не будет, но смысл запроса изменится. что будем считать дублем в этом случае? будут найдены 2 Саши 6-ти лет от роду, один Саша 7 лет, по два(е) Маши и Сережи каждого возраста и остальных пар возраст+имя по одному. как-то так.

    короче, не верь никому на слово :) читай книги по SQL, пробуй примеры.
     
  7. lastdays

    lastdays Активный пользователь

    С нами с:
    27 сен 2012
    Сообщения:
    410
    Симпатии:
    74
    Понятно, что вы имели ввиду по-второму пункту.
    У нас же есть конкретная задача, по-этому детей пока трогать не будем.

    1) Данные раздвоились.
    2) Удалить клоны


    Код (Text):
    1.  
    2. -- Структура таблицы `test`
    3. CREATE TABLE IF NOT EXISTS `test` (
    4.   `id` int(11) NOT NULL AUTO_INCREMENT,
    5.   `uid` int(11) NOT NULL DEFAULT '0',
    6.   PRIMARY KEY (`id`),
    7.   UNIQUE KEY `id` (`id`)
    8. ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
    9.  
    10. -- Данные таблицы `test`
    11. INSERT INTO `test` (`id`, `uid`) VALUES
    12. (1, 1),
    13. (2, 1),
    14. (3, 2),
    15. (4, 2),
    16. (5, 3),
    17. (6, 3),
    18. (7, 3);
    На выходе имеем:
    Код (Text):
    1.  id uid count
    2. === === ====
    3.   1   1  2
    4.   3   2  2
    5.   5   3  3
    Я кстати написал, что решение не очень. Но с задачей конкретной в тестовой таблице - справилось.
    В вашей задаче, группировки только по возрасту недостаточно.

    Спасибо за подробности!
     
  8. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
    т.е. ты не понял меня. с абстрагированием сложности?

    (выпилено многобукв)

    знаешь, когда задача не решается даже на твоих собственных тестовых данных, это не "не очень", а совсем никак. ты сам приводишь пример, где одно значение встретилось трижды - на нём будет прокол. ибо ты предлагаешь удалять какое-то найденное (единственное) значение из группы.

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

    ну и вообще, выполнять запросы в цикле не айс, надо избегать этого. вот получится на 200к строках 100к дублей, как это "решение" будет работать? 100000 запросов delete в цикле, ты серьезно?
     
    #8 artoodetoo, 19 июл 2016
    Последнее редактирование: 19 июл 2016
  9. lastdays

    lastdays Активный пользователь

    С нами с:
    27 сен 2012
    Сообщения:
    410
    Симпатии:
    74
    В цикле я только сформировал массив из первого попавшего айди, который после будет удален.
    Там где значение встретилось трижды, просто для наглядности.
    Разве вопрос стоял в оптимизации?

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

    Добавил 200 000 данных в таблицу, каждый второй клон
    Скрипт выполнялся 9.3395 сек. Удалено: 100000 строк
    Какие проблемы? на чем экономить? провести разовую процедуру страшно что ли.
    Давайте закончим дискуссию. Я вас понял.