Здравствуйте форумчане, столкнулся с такой проблемой, что в моей базе данных раздвоились некоторые строки, какие я не знаю и искать их среди 200к строк очень напряжно. Нет ли какого-то способа быстро найти такие строки-клоны и удалить их?
Решение не ахти, но "прокатит". БЭкап стоит сделать, прежде чем удалять. PHP: $del = array(); $data = $db->query("SELECT `id`, `uid`, count(1) as `count` FROM `test` GROUP BY `uid`"); if ( count ( $data ) ) { foreach ( $data as $d ) { //- Если записей, больше чем 1 if ( $d["count"] > 1 ) { $del[] = $d["id"]; } } unset( $data, $d ); //- Удаляем if ( count ( $del ) ) $db->query("DELETE FROM `test` WHERE `id` IN(".join(',',$del ).")",null); }
Не стоит благодарить. Это неудачная подсказка. 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
Так ТС и написал, что "раздвоились" строки, а не их по 10 клонов. з.ы. а можно подробнее по первому пункту?
@lastdays про возможность ошибки с вылетом: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by про логическую ошибку, даже если не вылетает: попробуй рассуждать логически. группировка это объединение нескольких строк в одну. если со значением группируемого (т.е. из фразы GROUP BY) поля всё понятно, то что должно быть на выходе в других полях? вот задачка "на пальцах": допустим есть школьный класс, в нём дети примерно одного возраста. вероятность повтора количества полных лет довольно велика. попробуем составить запрос для класса 1а: Код (Text): SELECT age, COUNT(*) AS cnt, first_name FROM pupils GROUP BY age WHERE class='1a' что именно должно получиться на выходе. допустим есть 30 учеников, из них 25-ти исполнилось 6, остальным 7. Что будет в поле first_name? Код (Text): age cnt first_name === === ========= 6 25 Саша 7 5 Маша Это нормально? Не думаю! Почему там Саша, почему не Антон? а если добавить в GROUP BY еще одно поле: GROUP BY age, first_name, то логической ошибки уже не будет, но смысл запроса изменится. что будем считать дублем в этом случае? будут найдены 2 Саши 6-ти лет от роду, один Саша 7 лет, по два(е) Маши и Сережи каждого возраста и остальных пар возраст+имя по одному. как-то так. короче, не верь никому на слово читай книги по SQL, пробуй примеры.
Понятно, что вы имели ввиду по-второму пункту. У нас же есть конкретная задача, по-этому детей пока трогать не будем. 1) Данные раздвоились. 2) Удалить клоны Код (Text): -- Структура таблицы `test` CREATE TABLE IF NOT EXISTS `test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `uid` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ; -- Данные таблицы `test` INSERT INTO `test` (`id`, `uid`) VALUES (1, 1), (2, 1), (3, 2), (4, 2), (5, 3), (6, 3), (7, 3); На выходе имеем: Код (Text): id uid count === === ==== 1 1 2 3 2 2 5 3 3 Я кстати написал, что решение не очень. Но с задачей конкретной в тестовой таблице - справилось. В вашей задаче, группировки только по возрасту недостаточно. Спасибо за подробности!
т.е. ты не понял меня. с абстрагированием сложности? (выпилено многобукв) знаешь, когда задача не решается даже на твоих собственных тестовых данных, это не "не очень", а совсем никак. ты сам приводишь пример, где одно значение встретилось трижды - на нём будет прокол. ибо ты предлагаешь удалять какое-то найденное (единственное) значение из группы. далее, ты не понял, что надо конкретизировать какой именно id должен появиться в выдаче. полагаешься на случайность или какую-то наблюдаемую но недокументированную закономерность. это фэйл. ну и вообще, выполнять запросы в цикле не айс, надо избегать этого. вот получится на 200к строках 100к дублей, как это "решение" будет работать? 100000 запросов delete в цикле, ты серьезно?
В цикле я только сформировал массив из первого попавшего айди, который после будет удален. Там где значение встретилось трижды, просто для наглядности. Разве вопрос стоял в оптимизации? Ну пусть хоть 3 значения будет, ещё раз запустил скрипт и удалит клон. Повторю, это же единый глюк у человека, конечно надо писать изначально правильно, но тем не менее Добавил 200 000 данных в таблицу, каждый второй клон Скрипт выполнялся 9.3395 сек. Удалено: 100000 строк Какие проблемы? на чем экономить? провести разовую процедуру страшно что ли. Давайте закончим дискуссию. Я вас понял.